<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Fadet's coding box</title>
    <link>https://fadet-coding.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Fri, 10 Apr 2026 04:00:23 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>fadet</managingEditor>
    <item>
      <title>#4 실무 IntelliJ+Git 사용</title>
      <link>https://fadet-coding.tistory.com/100</link>
      <description>&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #555555; text-align: start;&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;* Portfolio 카테고리에 포스팅한 글들은 경력기술서나 포트폴리오에 첨부한 프로젝트 관련되어 작성한 내용임을 알립니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #555555; text-align: start;&quot;&gt;* 내용에 대한 댓글은 언제나 환영입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;1. 관련 프로젝트 및 업무 개요&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt; * 사내 진행했던 프로젝트로 실제 커밋 이력은 비공개이며 포스팅의 모든 사항은 공개 가능한 범위에서만 작성합니다. &lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;프로젝트 및 업무 명&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;협업 내 퍼블리셔/프론트 팀 git 총괄 관리&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;개발 환경&lt;/b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;intelliJ&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;Git, gitLab&lt;/span&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;2. 문제 분석 및 최초 Revision&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;* 포스팅에 사용된 사항은 실제 사내 사용 사례가 아닌 전부 예시임&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제사항&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;퍼블리셔/프론트엔드 팀과의 협업 과정에서 생기는 Git 관련 업무 시간 증가&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color: #000000; text-align: start;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1 Git 관리 환경으로 발생하는 협업 시간 증가&lt;br /&gt;2 잘못된 커밋 푸시로 인한 브랜치 복구 작업&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3 Feature 브랜치의 커밋 로그 간소화 작업&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;근거&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# Redmine 소요 시간 분석&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사내 업무 관리 툴인 Redmine 대시보드를 통한 분석 결과&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;퍼블리셔/프론트엔드 팀과의 협업이 포함된 일감들의 경우 통상 일감 대비 최소 20% 이상의 업무 시간이 소요&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# 팀내 회의 결과&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;협업 과정 중 잘못된 git 사용으로 인한 추가 잔업의 빈도가 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;퍼블리셔/프론트엔드 팀의 신규 인력 추가 이후 증가했다는 의견&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;분석&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1 Git 관리 환경 차이으로 발생하는 협업 시간 증가&lt;b&gt;&lt;br /&gt;&amp;gt; 팀간 사용 IDE의 차이로 인해 git 사용 환경이 다르며 기존의 branch 전략이 git 입문자들에게 다소 어려웠음&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;2 잘못된 커밋 푸시로 인한 브랜치 복구 작업&lt;b&gt;&lt;br /&gt;&amp;gt; &lt;span style=&quot;text-align: start;&quot;&gt;퍼블리셔/프론트엔드 팀에 git 사용 매뉴얼이 정확히 정착되지 않았음&lt;/span&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;3 Feature 브랜치의 커밋 로그 간소화 작업&lt;b&gt;&lt;br /&gt;&amp;gt; &lt;span style=&quot;text-align: start;&quot;&gt;git 입문자들에게 다소 난이도가 있는 reset 옵션 사용이 필요&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;논의 및 학습&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #000000; text-align: start;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;#1 Git 관리 환경으로 발생하는 협업 시간 증가&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사내 팀별 메인 업무에 사용되는 IDE는 아래와 같았음&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;퍼블리셔 : vscode&lt;br /&gt;프론트엔드 : vscode, Android Studio, Xcode &lt;br /&gt;백엔드(유지보수 포함) : IntelliJ&amp;nbsp;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 1 백엔드 팀에서 git을 사용하는 환경인 IntelliJ+git 통합 환경은 퍼블리셔/프론트엔드 팀이 사용하는 vscode의 git 사용과 방식이 많이 달랐으며 2 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;퍼블리셔/프론트엔드 팀은 상대적으로 cherry-pick, revert 등의 git 터미널을 통한 고급 기능 사용 미숙&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;또한 기존 사용하던 브랜치 전략은 jenkins+AKS를 사용하던 개발/배포 파이프라인에 맞춰 feature - dev - staging - main 으로 이어지는 git flow에 가까운 전략을 사용(release 대신 staging을 사용하며 hotfix 브랜치는 사용하지 않음)&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 과정에서 모든 팀이 동일한 권한으로 동일한 gitLab origin을 바라보며 푸시를 진행하므로 배포 속도가 느리기에 업무 시간을 줄이려는 과정에서 머지시 실수가 발생&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt; &lt;b&gt;&amp;gt; 최종 논의 결과 : &lt;span style=&quot;color: #006dd7; text-align: start;&quot;&gt;feature - staging - main으로 변경 및 팀별 푸시 권한 조정&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #000000; text-align: start;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;#2 잘못된 커밋 푸시로 인한 브랜치 복구 작업 &lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;백엔드 팀이 사용하는 IntelliJ+Git 통합 환경이므로 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;기존 git CLI와 다르게 동작&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프론트/퍼블리셔 팀이 사용하는 vscode 환경은 기본적으로 GUI만 제공하므로 기존 git CLI 정책과 동일&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;color: #333333; text-align: start; border-collapse: collapse; width: 90.0001%; height: 61px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-start=&quot;1585&quot; data-end=&quot;1798&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 9.06977%; height: 19px;&quot;&gt;환경&lt;/td&gt;
&lt;td style=&quot;width: 11.9768%; height: 19px;&quot;&gt;CLI 정책&lt;/td&gt;
&lt;td style=&quot;width: 25.3773%; height: 19px;&quot;&gt;push 전 자동 동기화 체크 여부&lt;/td&gt;
&lt;td style=&quot;width: 20.5366%; height: 19px;&quot;&gt;smart checkout 여부&lt;/td&gt;
&lt;td style=&quot;width: 24.3959%; height: 19px;&quot;&gt;conflict 발생시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-start=&quot;1716&quot; data-end=&quot;1755&quot;&gt;
&lt;td style=&quot;width: 9.06977%; height: 21px;&quot; data-start=&quot;1716&quot; data-end=&quot;1726&quot; data-col-size=&quot;sm&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;IntelliJ&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 11.9768%; height: 21px;&quot; data-start=&quot;1726&quot; data-end=&quot;1735&quot; data-col-size=&quot;sm&quot;&gt;다소 차이남&lt;/td&gt;
&lt;td style=&quot;width: 25.3773%; height: 21px;&quot; data-start=&quot;1735&quot; data-end=&quot;1740&quot; data-col-size=&quot;sm&quot;&gt;true&lt;/td&gt;
&lt;td style=&quot;width: 20.5366%; height: 21px;&quot; data-start=&quot;1740&quot; data-end=&quot;1746&quot; data-col-size=&quot;sm&quot;&gt;true&lt;/td&gt;
&lt;td style=&quot;width: 24.3959%; height: 21px;&quot; data-start=&quot;1746&quot; data-end=&quot;1755&quot; data-col-size=&quot;sm&quot;&gt;전용 &lt;b&gt;3-way merge 툴&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-start=&quot;1756&quot; data-end=&quot;1798&quot;&gt;
&lt;td style=&quot;width: 9.06977%; height: 21px;&quot; data-start=&quot;1756&quot; data-end=&quot;1769&quot; data-col-size=&quot;sm&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;vscode&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 11.9768%; height: 21px;&quot; data-start=&quot;1769&quot; data-end=&quot;1777&quot; data-col-size=&quot;sm&quot;&gt;거의 동일함&lt;/td&gt;
&lt;td style=&quot;width: 25.3773%; height: 21px;&quot; data-start=&quot;1777&quot; data-end=&quot;1782&quot; data-col-size=&quot;sm&quot;&gt;false&lt;/td&gt;
&lt;td style=&quot;width: 20.5366%; height: 21px;&quot; data-start=&quot;1782&quot; data-end=&quot;1789&quot; data-col-size=&quot;sm&quot;&gt;false&lt;/td&gt;
&lt;td style=&quot;width: 24.3959%; height: 21px;&quot; data-start=&quot;1789&quot; data-end=&quot;1798&quot; data-col-size=&quot;sm&quot;&gt;CLI 수준 메시지 + 간단 UX&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;* default configuration이며 intelliJ의 경우 로컬이 뒤쳐진 경우 push시 자동 3-way merge 처리됨&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 위의 표와 같은 협업시 주요 기능에 차이가 있으므로 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;vscode를 사용하는 퍼블리셔/프론트엔드 팀은 상대적으로 git에 대한 이해가 적은데 더해 &lt;/span&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;안전 장치를 더해 실수를 줄일 수 있는 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;IntelliJ와 비교하여 더 잦은 실수가 발생&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;하지만 퍼블리셔/프론트 팀과의 회의에서 팀의 대다수인 주임 이상급에서는 문제 발생이 적기에 이것만으로 Git Lens나 Git graph 등 vscode extension을 사용하는 것은 학습 비용이 더 클 것이라 결정했으며 타 팀이므로 그 결정을 존중하기로 하여 다른 방법을 논의함&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&amp;gt; 최종 논의 결과 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span&gt;1 fetch - pull - commit - push을 강제하는 매뉴얼을 도입 및 온보딩 교육 강화&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span&gt;2 PR(pull-request) 도입 후 머지 체크 프로세스 강화&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span&gt;3 cherry-pick, revert 등 복구 관련 명령어는 최종 백엔드 팀만 진행&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #000000; text-align: start;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;#3 Feature 브랜치의 커밋 로그 간소화 작업 &lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;업무 과정 중 Feature 브랜치에 너무 많은 커밋 로그가 발생하여 충돌이 발생하거나 이전 커밋으로 복구해야하는 경우 변경 이력에 대한 파악 시간이 증가하여 이 경우 로컬 squash를 통해 커밋 로그 간소화를 진행해야 함&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;* &lt;span style=&quot;text-align: start;&quot;&gt;squash의 경우 rebase -i(interactive&amp;nbsp; rebase) 옵션으로 fix-up과 유사한데 둘의 차이는 커밋 메세지 관리 차이&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;reset, rebase는 origin push를 잘못할 경우 커밋 유실 및 브랜치 꼬임의 위험성이 너무나도 커서 팀 정책으로 push 이후 커밋은 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;reset, rebase 절대 금지며 로컬에서만 허용&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;b&gt;&amp;gt; 최종 논의 결과 : push 이후 reset, rebase 사용 금지 / 단, 로컬에서 사용해야 한다면 반드시 팀간 상의 이후 진행&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;3. 결과&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;개선사항&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;#1 Git 관리 환경으로 발생하는 협업 시간 증가&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span&gt;@ 브랜치 전략 변경 및 팀별 푸시 권한 조정&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;기존의 git-flow에 가까운 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;b&gt;feature - dev - staging - main&lt;/b&gt; 전략에서&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;dev branch를 삭제하여 trunk based + &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;github-flow로 볼 수 있는 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;b&gt;feature - staging - main&lt;/b&gt; 전략으로 간소화&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: left;&quot;&gt;1-1&lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;span&gt; 이렇게 변경할 경우 staging 브랜치 품질 저하와 전체 프로세스의 안정성이 감소하지 않나?&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그 점을 보완하기 위해 &lt;b&gt;협업 프로젝트의 push 권한을 퍼블리셔/프론트 팀은 feature 까지로 제한&lt;/b&gt;했으며 뒤에서 언급하겠지만 &lt;b&gt;PR을 통해 수정된 부분에 대한 테스트가 완료된 커밋을 request시 백엔드 팀에서 머지&lt;/b&gt;하는 것으로 논의 완료&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;gt; 기존 dev 브랜치의 경우 백엔드 팀 입장에선 &lt;b&gt;staging에 푸시 되기 전 로컬 커밋과 프로세스 상 차이가 없으며 dev 브랜치는 직접적인 배포 파이프라인과 연결되어 있지 않으므로 &lt;span style=&quot;color: #006dd7;&quot;&gt;관리 용이와 배포 속도 향상&lt;/span&gt;&lt;/b&gt;이라는 장점에 대비해 &lt;span style=&quot;color: #ee2323;&quot;&gt;전략 변경의 비용&lt;/span&gt;이 거의 없음&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;* 단, 이 결정은 사내 프로젝트의 특성에 기인하며 환경에 따라 완전히 틀린 결정일 수 있음을 유의&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;#2 잘못된 커밋 푸시로 인한 브랜치 복구 작업&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span&gt;@a fetch - pull - commit - push을 강제하는 매뉴얼을 도입 및 온보딩 교육 강화&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;온보딩 교육 매뉴얼 추가부터 팀내 교육시에도 git 사용시 반드시 &lt;b&gt;&lt;span&gt;fetch - pull - commit - push를 의무화하도록 강조하고&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;span&gt;만약 이를 지키지 않아 conflict나 denied 발생시 force push 등 자율적인 해결이 아닌 반드시 상위 직급에게 보고하도록 정책 수정&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span&gt;@b PR(pull-request) 도입 후 머지 체크 프로세스 강화&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;앞서 언급한 퍼블리셔/프론트 팀 작업 및 테스트 완료 후 해당 커밋에 대해 reviewer를 백엔드 팀에 지정하도록 PR을 강제하여 잘못된 커밋 푸시 빈도를 줄이고 approve 후 merge 과정에서 한 번 더 체크하여 staging 머지시 생길 충돌을 사전에 예방&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로세스상 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;작은 PR을 도입하기는 힘드나&lt;/span&gt; 1 squash를 통해 커밋 히스토리를 읽기 쉽게 간소화하고 2 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;퍼블리셔/프론트 팀의 Author는 request시 매뉴얼에 따라 커밋 분류, 커밋 메세지를 작성 을 통해 효율적인 PR 단계가 진행되도록 함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span&gt;@c cherry-pick, revert 등 복구 관련 명령어는 최종 백엔드 팀만 진행&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;팀간 협의 중 앞서 퍼블리셔/프론트 팀은 별도의 extension을 사용하지 않기로 결정했으므로 CLI 자체로는 하기 힘든 git diff 후 수동 복구, revert, cherrypick, &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fix 등&lt;/span&gt;은 intelliJ를 사용하는 백엔드 팀에서 진행&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;blockquote style=&quot;color: #000000; text-align: start;&quot; data-ke-style=&quot;style2&quot;&gt;#3&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Feature 브랜치의 커밋 로그 간소화 작업&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;feature의 커밋이 ground rule로 정한 10개를 넘기거나 PR 검토시 적절하지 않다 판단되는 경우 작업 중인 로컬 브랜치 내에서 squash 작업을 진행함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;* fix-up은 커밋 메세지 폐기로 인해 사용하지 않음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;* remote가 아닌 반드시 로컬 브랜치에서만 reset, rebase 명령어를 수행&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;4. 추후 이슈 및 대응&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h4 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이슈 발생 사항&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt; &lt;b&gt;#1 stash&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;일반적으로 수정사항이 존재하는데 잠시 다른 브랜치로 checkout하고 싶은 경우 git CLI는 stash라는 명령어를 통해 진행할 수 있습니다. 하지만 IntelliJ+git 통합 환경의 경우 smart checkout을 제공하여 stash를 잘 사용하지 않고 만약 필요하다면 stash 명령어를 대신하여 비슷하게 다음과 같이 사용할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;* 임시 저장 관련해선 Shelve가 가장 편리하지만 이는 git 기능이 아닌 &lt;span style=&quot;text-align: start;&quot;&gt;IntelliJ 단독 제공이므로 제외하였습니다&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1 다른 브랜치 체크 아웃 전 로컬 변경사항을 우선 작업 중인 브랜치에 커밋(* 푸시하지 않음)&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;* untracked 파일이 존재하는 등 smart checkout을 사용하지 못하는 경우&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2 다른 브랜치에서 작업 후 다시 작업 브랜치로 돌아와서 최신 커밋에 대해 아래 그림과 같이 reset soft 수행&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;*&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;아래 이미지는 예시 이미지이며 reset soft시 사용된 브랜치가 아님&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;깃 1.png&quot; data-origin-width=&quot;883&quot; data-origin-height=&quot;730&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xHGkP/btsQoQeFsc5/wthZBtw56Jn0YKezWPJ79K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xHGkP/btsQoQeFsc5/wthZBtw56Jn0YKezWPJ79K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xHGkP/btsQoQeFsc5/wthZBtw56Jn0YKezWPJ79K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxHGkP%2FbtsQoQeFsc5%2FwthZBtw56Jn0YKezWPJ79K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;546&quot; height=&quot;451&quot; data-filename=&quot;깃 1.png&quot; data-origin-width=&quot;883&quot; data-origin-height=&quot;730&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stash 명령어의 경우 기본적으로 여러 개가 쌓일 경우 stash list를 사용하더라도 직관성이 떨어지므로 업무시 위와 같은 reset soft를 자주 사용했었는데 병합 충돌이 해결되지 않은 브랜치거나 reset 대상 브랜치를 잘못 선택하는 경우 기대와 다른 동작을 가져옴&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt; &lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&amp;gt; 1 반드시 feature 브랜치에만 사용 2 변경 사항이 너무 많은 브랜치는 기존대로 stash를 사용&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&amp;nbsp;* 변경 사항이 적을 경우 어차피 로컬에서의 커밋만 존재하는 브랜치이므로 폐기 후 remote에서 다시 브랜치를 가져와 변경 사항 추가&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;추가 고려 사항&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;#1 퍼블리셔/프론트 팀장에게 IntelliJ+git 사용법을 공유하여 더욱 효율적인 프로세스로의 변경 가능성 논의&lt;br /&gt;#2 추후 팀 규모가 커질 경우 다시 git flow(feature-dev-staging-main) 전략 롤백&amp;nbsp;&lt;br /&gt;#3 프로세스상 PR 크기가 커질 수 밖에 없는 구조이나 이후 작은 PR로의 변경 가능성 논의&lt;/blockquote&gt;</description>
      <category>Portfolio</category>
      <category>git</category>
      <category>IntelliJ</category>
      <category>rebase</category>
      <category>squash</category>
      <author>fadet</author>
      <guid isPermaLink="true">https://fadet-coding.tistory.com/100</guid>
      <comments>https://fadet-coding.tistory.com/100#entry100comment</comments>
      <pubDate>Sun, 7 Sep 2025 19:10:30 +0900</pubDate>
    </item>
    <item>
      <title>#3 사내 보안 취약점 대응 2</title>
      <link>https://fadet-coding.tistory.com/99</link>
      <description>&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #555555; text-align: start;&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;* Portfolio 카테고리에 포스팅한 글들은 경력기술서나 포트폴리오에 첨부한 프로젝트 관련되어 작성한 내용임을 알립니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #555555; text-align: start;&quot;&gt;* 내용에 대한 댓글은 언제나 환영입니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;❗ 사내 보안 취약점 대응 포스팅은&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;#2 사내 보안 취약점 대응1 - 패킷 파라미터 변조&lt;/span&gt; / #3 사내 보안 취약점 대응2 - XSS 및 서버 정보 노출&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;두개의 포스팅으로 나뉘어져 있습니다.&lt;br /&gt;이전 글 링크 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://fadet-coding.tistory.com/98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://fadet-coding.tistory.com/98&lt;/a&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;1. 관련 프로젝트 및 업무 개요&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;* 사내 진행했던 프로젝트로 github repository나 실제 프로덕트 코드는 비공개이며 포스팅의 모든 사항은 공개 가능한 범위에서만 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;프로젝트 및 업무 명(공개 가능)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사내 보안 취약점 분석 및 수정&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;개발 환경&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;(공개 가능)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;Vue.js 2.x&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;intelliJ&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;JAVA 1.8 / Spring Boot 2.7.x / myBatis 2.x&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Fiddler Classic / BurpSuite&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;Tomcat&amp;nbsp; / Jenkins&amp;nbsp; / Azure Kubernetes Service&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;2. 문제 분석 및 최초 Revision&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;* 포스팅에 사용된 코드 및 이미지는 실제 프로덕트에 사용되지 않은 전부 예시임&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제사항&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;보안 보고서를 기반으로 현재 내부 시스템 취약점 분석 및 수정 요구&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;단, 현실적으로 모든&amp;nbsp;&amp;nbsp;&lt;b&gt;OWASP&amp;nbsp;권고 사항&lt;/b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;에 대한 이행은 불가능하므로 critical한 취약점에 대한 수정 진행&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;(이번 포스트에서 2,3번 항목에 대해 기술, 1번은 이전 포스트 참조)&lt;/span&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color: #000000; text-align: start;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;1 특정 수정 및 삭제 비즈니스 로직에서 HTTP 요청 패킷의 쿼리 파라미터 변조시 타 유저 데이터 변경 가능&lt;/span&gt;&lt;br /&gt;&lt;b&gt;2 클라이언트 input에 XSS 공격 시도시 &lt;span style=&quot;color: #006dd7;&quot;&gt;악의적인 script 작동&lt;span style=&quot;color: #666666;&quot;&gt; &lt;b&gt;(이번 포스트)&lt;/b&gt; &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;3 특정 url 요청시 &lt;span style=&quot;color: #006dd7;&quot;&gt;WAS 서버 정보 노출&lt;span style=&quot;color: #666666;&quot;&gt; &lt;b&gt;(이번 포스트)&lt;/b&gt; &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;근거&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# (1-3 공통) BurpSuite 분석&lt;/b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image01.png&quot; data-origin-width=&quot;870&quot; data-origin-height=&quot;594&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHAWGN/btsQmip6qPx/PN3Ez5eMm3MxRbYsiXiW31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHAWGN/btsQmip6qPx/PN3Ez5eMm3MxRbYsiXiW31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHAWGN/btsQmip6qPx/PN3Ez5eMm3MxRbYsiXiW31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHAWGN%2FbtsQmip6qPx%2FPN3Ez5eMm3MxRbYsiXiW31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;870&quot; height=&quot;594&quot; data-filename=&quot;image01.png&quot; data-origin-width=&quot;870&quot; data-origin-height=&quot;594&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# (1-2 공통)&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fiddler debugging을 사용한 모의 해킹 시도&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image02.png&quot; data-origin-width=&quot;869&quot; data-origin-height=&quot;523&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0Z5Nd/btsQofr6spU/cyUbZaI19za6KnTKczczO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0Z5Nd/btsQofr6spU/cyUbZaI19za6KnTKczczO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0Z5Nd/btsQofr6spU/cyUbZaI19za6KnTKczczO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0Z5Nd%2FbtsQofr6spU%2FcyUbZaI19za6KnTKczczO0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;869&quot; height=&quot;523&quot; data-filename=&quot;image02.png&quot; data-origin-width=&quot;869&quot; data-origin-height=&quot;523&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# (3) 특정 URL 접속시 서버 정보 노출(staging, production 공통)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;tomcat_info_01.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;395&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnmOXP/btsQmENhSue/GlJzMhRtVeHMNotaXGt0cK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnmOXP/btsQmENhSue/GlJzMhRtVeHMNotaXGt0cK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnmOXP/btsQmENhSue/GlJzMhRtVeHMNotaXGt0cK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnmOXP%2FbtsQmENhSue%2FGlJzMhRtVeHMNotaXGt0cK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;395&quot; data-filename=&quot;tomcat_info_01.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;395&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;분석&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;b&gt;1 HTTP 요청 패킷의 서버 수신 성공으로 인한 검증 로직 부재 의심&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;b&gt;&amp;gt; WAS에 파라미터 검증 로직 존재 x&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2 &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;네트워크 통신 패킷 진입 전 클라이언트 submit부터 &amp;lt;script ... 코드 필터링 제외 &lt;b&gt;(이번 포스트)&lt;/b&gt; &lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;gt; Vue.js 기반 클라이언트의 v-html 태그의 XSS 공격 취약점 발견&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;3 특정 URL의 에러 발생 시점이 dispatcher servlet 진입 이전임을 확인&lt;b&gt; (이번 포스트) &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;gt; staging, production 내부 server.xml의 VALVE 설정 변경을 통해 서버 정보 노출 레벨 조정 가능&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;논의 및 학습&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;#2 클라이언트 input에 XSS 공격 시도시 악의적인 script 작동&lt;/b&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;해당 XSS 취약점은 JSP와 Vue.js 클라이언트 모두 발생했으므로 업무상 중요도를 고려하여 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;Vue.js 관련 항목 먼저 파악을 시작하여 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;아래 순서로 논의 후 적용 방식 결정&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;2-1 Vue.js로 작성된 클라이언트에 XSS 공격이 가능한가?&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;기존 알고있던 지식으론 Vue.js로 작성된 클라이언트 페이지는 input 자동 이스케이프를 통해 XSS 공격이 불가능한 것으로 알고 있었음&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 추가 확인 결과 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;Vue.js 템플릿 내 v-html 태그는 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;input 자동 이스케이프가 되지 않아 XSS 공격이 가능&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt; &lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;2-2 그렇다면 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;v-html을 &lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;v-text나 &lt;/span&gt;{{}}같은 mustache로 &lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;변경하면&lt;/span&gt; 간단하지 않나?&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;근본적으로&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;1 v-html은 innerHTML&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;2 v-text는 textContent이며 &lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;{{}} 역시 Vue.js가 자동으로 escape처리를 진행해줌&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt; &lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;2-3 JSP의 스크립틀릿이나 EL 태그를 JSTL의 c:out으로 변경하면 &lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;간단하지 않나?&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1 Vue.js의 경우와 동일하게 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;innerHTML 기반으로 작동해야만 하는 요소는 c:out 태그와 사용 목적이 애초에 다르며 &amp;lt;c:out&amp;gt;은 v-text와 더 유사&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;2 거기에 더해 JSP는 Vue와 다르게 기본적으로 이스케이프 처리를 제공하지 않음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&amp;gt; 최종 논의 결과&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;@Vue.js&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;1 &lt;span style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: left;&quot;&gt;v-text나&amp;nbsp;&lt;/span&gt;{{}}로 사용해도 무방한 요소라면 수정 가능&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;2 위의 경우가 아니라면 vue-dompurify-html 라이브러리를 사용하여 escape&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;* &lt;span style=&quot;background-color: #ffffff; text-align: left;&quot;&gt;sanitize를 통한 필터링은 사용하지 않았으므로 스킵&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;@JSP&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;1 &amp;lt;c:out&amp;gt; 태그를 사용 가능한 요소의 경우 변환시 escapeXml=&quot;false&quot; 옵션을 추가하여 수정 가능&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;2 위의 경우가 아니라면 OWASP Java HTML Sanitizer 라이브러리를 사용하여 escape 및 &lt;span style=&quot;background-color: #ffffff; text-align: left;&quot;&gt;sanitize&lt;/span&gt; &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;#3 특정 url 요청시 WAS 서버 정보 노출&lt;/b&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;span&gt;WAS로 톰캣을 사용하는 경우 기본적으로 서블릿 컨테이너를 통과한 이상 요청은 &lt;span style=&quot;background-color: #ffffff; color: #7b6d6d; text-align: left;&quot;&gt;web.xml&lt;/span&gt; 설정을 통해 에러 페이지가 서빙이 되지만 이 항목은 아니므로 &lt;/span&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;아래 순서로 논의 후 적용 방식 결정&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: left;&quot;&gt;3-1&lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt; 에러가 발생하는 &lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;특정 URL들의 공통점은 무엇인가?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;보안 관련된 사항이므로 요구사항의 URL을 특정하여 밝힐 수는 없지만 서블릿 컨테이너 진입 전, 즉 애플리케이션 레벨에서 핸들링 불가능한 경우(예를 들어, 요청 헤더/바디 파싱 불가나 SSL Handshake, 인증서 검증 실패 등)&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;톰캣 내부 web.xml, 애플리케이션 내 @ControllerAdvice, ExceptionHandler가 처리하지 못함&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;3-2 컨테이너 기본 이미지에 포함된 server.xml 설정만 변경하면 간단한 작업 아닌가?&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;문제가 발생한 관리자 페이지의 사내 파이프라인은 부트의 내장 톰캣이 아닌&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;로컬, 개발, 배포 환경&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;각각 별도의&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;외장 톰캣을&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용했으므로 적용되는 &lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;server.xml을 모두 따로 찾아 수정해야만 했음&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;* 로컬의 경우 요구사항 밖이었지만 비교적 간단한 부분이며 추후 타 개발자의 유지보수시 혼란 방지를 위하여 함께 수정&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;b&gt;&amp;gt; 최종 논의 결과 : 내부 server.xml의 VALVE 설정 변경&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;3. 결과&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;개선사항&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;#2 클라이언트 input에 XSS 공격 시도시 악의적인 script 작동&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;@ Vue.js&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1757160118752&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- as-is --&amp;gt;
&amp;lt;div v-html=&quot;userInput&quot;&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;!-- to-be --&amp;gt;
&amp;lt;div v-text=&quot;userInput&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;{{ userInput }}&amp;lt;/div&amp;gt;
&amp;lt;!-- sanitize 라이브러리 적용 --&amp;gt;
&amp;lt;div v-dompurify-html=&quot;richText&quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;@JSP&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1757160178897&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- as-is --&amp;gt;
&amp;lt;div&amp;gt;&amp;lt;%= request.getParameter(&quot;userInput&quot;) %&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;${userInput}&amp;lt;/div&amp;gt;

&amp;lt;!-- c:out 태그 사용 --&amp;gt;
&amp;lt;div&amp;gt;&amp;lt;c:out value=&quot;${userInput}&quot; escapeXml=&quot;false&quot;/&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;!-- OWASP Java HTML Sanitizer 사용 (라이브러리 적용을 위한 pom.xml 및 부트 로직 생략) --&amp;gt;
&amp;lt;div&amp;gt;&amp;lt;%= SanitizerUtil.sanitize(request.getParameter(&quot;comment&quot;)) %&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;* sanitizer시 script 태그를 포함한 img 태그 멀티미디어, 폼 입력, 이벤트 계열 태그 모두 포함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;#3 특정 url 요청시 WAS 서버 정보 노출&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;@a 로컬&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음1.png&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;214&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDRTkK/btsQmfAi1NU/MH7F6kYmaPx19Mzmslel0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDRTkK/btsQmfAi1NU/MH7F6kYmaPx19Mzmslel0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDRTkK/btsQmfAi1NU/MH7F6kYmaPx19Mzmslel0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDRTkK%2FbtsQmfAi1NU%2FMH7F6kYmaPx19Mzmslel0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1214&quot; height=&quot;214&quot; data-filename=&quot;제목 없음1.png&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;214&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;Configuration에 등록된 외장 톰캣 디렉토리의 server.xml 변경&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;@b 개발&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;{ $CATALINA_HOME }/usr/local/tomcat/conf/server.xml 내부 valve&lt;/p&gt;
&lt;pre id=&quot;code_1757160911493&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Host ...&amp;gt;
	...
	&amp;lt;Valve className=&quot;org.apache.catalina.valves.ErrorReportValve&quot; showReport=&quot;false&quot; showServerInfo=&quot;false&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;* 특정 &lt;span style=&quot;text-align: start;&quot;&gt;에러 페이지를 반환하려면&lt;/span&gt;&amp;nbsp;ErrorReportValve 대신 CustomValve를 생성해야 함&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7; text-align: start;&quot;&gt;@c 배포&lt;/span&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;* 사내 정보 노출 우려로 비공개&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;server.xml의 절대 경로 자체가 개발과 달랐으며 최상위 환경 변수 시작 디렉토리도 달랐으나&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;개발과 동일하게 적용되는 경로의 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;server.xml 정보 수정&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;* 컨테이너 자체가 아닌 이미지 빌드 파이프라인 내부 &lt;span style=&quot;text-align: start;&quot;&gt;server.xml을 변경해야 함&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;테스트&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;2 클라이언트 input에 XSS 공격 시도시 악의적인 script 작동&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;# BurpSuite를 통해 악의적인 스크립트 삽입시&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;523&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUdzPB/btsQnGX8OpB/B301mVXNtNKbUuKCGtnSQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUdzPB/btsQnGX8OpB/B301mVXNtNKbUuKCGtnSQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUdzPB/btsQnGX8OpB/B301mVXNtNKbUuKCGtnSQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUdzPB%2FbtsQnGX8OpB%2FB301mVXNtNKbUuKCGtnSQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;523&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;523&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;위와 같이 script 태그 escape 처리 완료&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;* 업무 대부분 fiddler를 사용했으나 최종 통과를 위해 &lt;span style=&quot;text-align: start;&quot;&gt;BurpSuite도 동시 확인(fiddler도 마찬가지로 통과)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;* Vue.js, JSP 페이지 모두 escape 확인 완료했으나 방식이 동일하므로 이미지 제외&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;3 특정 url 요청시 WAS 서버 정보 노출&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;# 보안 취약점 보고서에 명시된 특정 URL 삽입시&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;그림2.jpg&quot; data-origin-width=&quot;2302&quot; data-origin-height=&quot;462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dc7QWu/btsQn0otl3d/MnmKWQj8WinjZWXszH7WP1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dc7QWu/btsQn0otl3d/MnmKWQj8WinjZWXszH7WP1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dc7QWu/btsQn0otl3d/MnmKWQj8WinjZWXszH7WP1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdc7QWu%2FbtsQn0otl3d%2FMnmKWQj8WinjZWXszH7WP1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2302&quot; height=&quot;462&quot; data-filename=&quot;그림2.jpg&quot; data-origin-width=&quot;2302&quot; data-origin-height=&quot;462&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;* 포스트 중간에 언급한대로 커스텀 에러 페이지 반환을 위한 valve 생성이 권장&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;4. 추후 이슈 및 대응&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이슈 발생 사항&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;해당 없음&lt;/p&gt;
&lt;h4 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;추가 고려 사항&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1 포스팅에 언급했듯 커스텀 에러 페이지 반환을 위해 customValve로의 수정이 필요&lt;br /&gt;2 XSS 취약점 분석 이후 회고 과정에서 CSRF 공격 가능성도 발견했으나 업무 기간 문제로 인해 추후 점검 예정&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Portfolio</category>
      <category>escape</category>
      <category>innerHTML</category>
      <category>Tomcat</category>
      <category>v-html</category>
      <category>XSS</category>
      <author>fadet</author>
      <guid isPermaLink="true">https://fadet-coding.tistory.com/99</guid>
      <comments>https://fadet-coding.tistory.com/99#entry99comment</comments>
      <pubDate>Sat, 6 Sep 2025 22:09:53 +0900</pubDate>
    </item>
    <item>
      <title>#2 사내 보안 취약점 대응 1</title>
      <link>https://fadet-coding.tistory.com/98</link>
      <description>&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #555555; text-align: start;&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;* Portfolio 카테고리에 포스팅한 글들은 경력기술서나 포트폴리오에 첨부한 프로젝트 관련되어 작성한 내용임을 알립니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #555555; text-align: start;&quot;&gt;* 내용에 대한 댓글은 언제나 환영입니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style2&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;❗ 사내 보안 취약점 대응 포스팅은 &lt;b&gt;#2 사내 보안 취약점 대응1 - 패킷 파라미터 변조 / &lt;span style=&quot;color: #9d9d9d;&quot;&gt;#3 사내 보안 취약점 대응2 - XSS 및 서버 정보 노출&lt;/span&gt;&lt;/b&gt; 두개의 포스팅으로 나뉘어져 있습니다. &lt;br /&gt;다음 글 링크 : &lt;a title=&quot;https://fadet-coding.tistory.com/98&quot; href=&quot;https://fadet-coding.tistory.com/99&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://fadet-coding.tistory.com/99&lt;/a&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;1. 관련 프로젝트 및 업무 개요&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;* 사내 진행했던 프로젝트로 github repository나 실제 프로덕트 코드는 비공개이며 포스팅의 모든 사항은 공개 가능한 범위에서만 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;프로젝트 및 업무 명(공개 가능)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사내 보안 취약점 분석 및 수정&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;개발 환경&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;(공개 가능)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;Vue.js 2.6.x&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;intelliJ&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;JAVA 1.8 / Spring Boot 2.7.x / myBatis 2.3&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Fiddler Classic / BurpSuite&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;Tomcat 9.0.x / Jenkins 2.3x / Azure Kubernetes Service&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;2. 문제 분석 및 최초 Revision&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;* 포스팅에 사용된 코드 및 이미지는 실제 프로덕트에 사용되지 않은 전부 예시임&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제사항&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;보안 보고서를 기반으로 현재 내부 시스템 취약점 분석 및 수정 요구&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;단, 현실적으로 모든&amp;nbsp; &lt;b&gt;OWASP 권고 사항&lt;/b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;에 대한 이행은 불가능하므로 critical한 취약점에 대한 수정 진행&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;(이번 포스트에선 1번, 다음 포스트에서 2,3번 항목에 대해 기술)&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;1 특정 수정 및 삭제 비즈니스 로직에서 &lt;span style=&quot;color: #006dd7;&quot;&gt;HTTP 요청 패킷의 쿼리 파라미터 변조시 타 유저 데이터 변경 가능&lt;/span&gt; (이번 포스트)&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;2 클라이언트 input에 XSS 공격 시도시 악의적인 script 작동&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;3 특정 url 요청시 WAS 서버 정보 노출&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;근거&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# (1-3 공통) BurpSuite 분석&lt;/b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image01.png&quot; data-origin-width=&quot;870&quot; data-origin-height=&quot;594&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cx0uMM/btsQl0bhBhy/8kjPKSB3vtQi2WzlnBgvK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cx0uMM/btsQl0bhBhy/8kjPKSB3vtQi2WzlnBgvK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cx0uMM/btsQl0bhBhy/8kjPKSB3vtQi2WzlnBgvK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcx0uMM%2FbtsQl0bhBhy%2F8kjPKSB3vtQi2WzlnBgvK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;870&quot; height=&quot;594&quot; data-filename=&quot;image01.png&quot; data-origin-width=&quot;870&quot; data-origin-height=&quot;594&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# (1-2 공통)&amp;nbsp; &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fiddler debugging을 사용한 모의 해킹 시도&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image02.png&quot; data-origin-width=&quot;869&quot; data-origin-height=&quot;523&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XQnd9/btsQmGwC3h3/kyNfb17hkn43lSI8yQY59K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XQnd9/btsQmGwC3h3/kyNfb17hkn43lSI8yQY59K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XQnd9/btsQmGwC3h3/kyNfb17hkn43lSI8yQY59K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXQnd9%2FbtsQmGwC3h3%2FkyNfb17hkn43lSI8yQY59K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;869&quot; height=&quot;523&quot; data-filename=&quot;image02.png&quot; data-origin-width=&quot;869&quot; data-origin-height=&quot;523&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;# (3) 특정 URL 접속시 서버 정보 노출(staging, production 공통)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;tomcat_info_01.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;395&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQUgIr/btsQlrNKZhh/uRo73IAs9IXrSF7KBoBisK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQUgIr/btsQlrNKZhh/uRo73IAs9IXrSF7KBoBisK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQUgIr/btsQlrNKZhh/uRo73IAs9IXrSF7KBoBisK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQUgIr%2FbtsQlrNKZhh%2FuRo73IAs9IXrSF7KBoBisK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;395&quot; data-filename=&quot;tomcat_info_01.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;395&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;분석&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;1 HTTP 요청 패킷의 서버 수신 성공으로 인한 검증 로직 부재 의심&lt;b&gt; (이번 포스트)&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;gt; WAS에 파라미터 검증 로직 존재 x&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;2 네트워크 통신 패킷 진입 전 클라이언트 submit부터 &amp;lt;script ... 코드 필터링 제외&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&amp;gt; Vue.js 기반 클라이언트의 v-html 태그의 XSS 공격 취약점 발견&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;3 특정 URL의 에러 발생 시점이 dispatcher servlet 진입 이전임을 확인&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&amp;gt; staging, production 내부 server.xml의 VALVE 설정 변경을 통해 서버 정보 노출 레벨 조정 가능&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;논의 및 학습&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;#1 특정 수정 및 삭제 비즈니스 로직에서 HTTP 요청 패킷의 쿼리 파라미터 조작 변조시 타 유저 데이터 변경 가능&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 취약점은 &lt;b&gt;Insecure Direct Object Reference (IDOR)&lt;/b&gt; 취약점 유형으로 분류되며 서버 측 검증이 필요하다는 판단으로 아래 순서로 논의 후 적용 방식 결정&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;1-1 세션 request 기반 인증 정보를 통해 검증 가능한가?&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&amp;gt; 기존에 서버 세션을 사용하지 않으므로 검증만을 위해 세션을 활성화시키는 것은 부적절하다는 결론&lt;/span&gt; &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt; &lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;1-2 개별 비즈니스 로직마다 선행 검증을 추가하면 매번 요구사항 발생마다 비용이 들지 않나?&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;위 논의 사항은 매우 적절하여 다음과 같은 대체 방식을 고려&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;1. Spring Security의 @PreAuthorize나 AuthorizationManager 사용&lt;br /&gt;2. 별도의 공통 인가용 AuthorizationService 적용&lt;br /&gt;3. 리포지토리 레벨에서 소유권 보장 &lt;br /&gt;4. Custom AOP advice 적용 후 annotation을 통한 검증&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;하지만 위 모든 대체 방식은 다음의 이유로 논의 과정에서 제외&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1. Spring Security 사용&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&amp;gt; 현재 시스템의 Interceptor 기반 인증/인가에서 Spring Security 도입은 학습/적용 비용 문제로 인해 현실적으로 불가능&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757069483857&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;PostResponseDto findByIdAndUserId(Long postId, Long userId);&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;2. 위와 같은 리포지토리 레벨에서 소유권 보장&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&amp;gt; 위 방식은 mapper 작성시 누락 가능성이 높아 개발자에게 책임을 전가하는 것이므로 논의에서 제외&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757069793907&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckOwnership {
    String resourceIdParam();
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;3. 위와 같은 Custom AOP advice 생성 후 annotation을 통한 검증&lt;br /&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&amp;gt; 1 AOP 기반으로 검증을 모듈화시 개발자들의 추가 AOP 학습 비용이 너무 큼 2 AOP의 경우 런타임 프록시를 통해 동작하므로 런타임 성능 오버헤드 발생 가능성 3 유지보수를 위한 디버깅이 복잡해지고 @Transactional 같은 다른 AOP 기능과의 충돌 우려&lt;/b&gt; 같은 이유들로 반려&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757069302733&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class AuthorizationService {
    public void checkUserId(Long resourceUserId, Long authenticatedUserId) {
        if (!resourceUserId.equals(authenticatedUserId)) {
            throw new AccessDeniedException(&quot;권한 없음&quot;);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;4. 위와 같은 별도의 공통 인가용 AuthorizationService 적용&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;gt; 현재 적용시 오히려 service를 두번 호출하게 되어 코드 가독성과 SRP 위반으로 서비스가 비대해져 유지보수 비용이 더 커지므로 반려. 하지만&lt;/span&gt; 1 서비스간 책임 분리를 통한 SRP 준수 2 비즈니스 로직별 공통 검증이 많아질 경우 매우 효율적 이라는 근거로 인해 추후 논의 예정&lt;/b&gt;&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;1-3 그렇다면 검증을 진행할 component는?&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;이론상 서버 측 객체별 접근 제어는 주요 layer 마다 적용해야 하는 것이 맞으나 실무적으로 보안 책임을 집중시키는 것이 맞다는 판단 후&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;검증을 적용할 component 후보는 &lt;b&gt;controller, service, mapper(repository)&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;이 중 비즈니스 로직별 유저 소유 확인 가능한 &lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;component는 &lt;b&gt;service와 mapper&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757067527673&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* 예시 코드로 글의 길이를 위해 format을 일부러 줄임 */
&amp;lt;update id=&quot;updatePost&quot; parameterType=&quot;map&quot;&amp;gt;
  &amp;lt;selectKey keyProperty=&quot;ValidUserId&quot; resultType=&quot;long&quot; order=&quot;BEFORE&quot;&amp;gt;
    SELECT user_id FROM posts
    WHERE post_id = #{postId}
  &amp;lt;/selectKey&amp;gt;
  
  UPDATE posts SET title = '${title}', content = '${content}'
  WHERE post_id = ${postId} AND user_id = ${ValidUserId}
&amp;lt;/update&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 경우&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1 mapper에서 selectKey를 사용하여 record filtering도 가능은 하지만 이럴 경우 &lt;b&gt;쓸모 없는 DBMS 사용&lt;/b&gt;이 발생&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2 하나의 update 트랜잭션이라 하더라도 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;selectKey를 사용하면 원자적인 작업 단위가 아니므로 트랜잭션 격리 수준이나 옵티마이저의 실행 방식에 따라서 안전하지 않을 수 있기 때문에 &lt;b&gt;의존적인&lt;/b&gt; selectKey 사용은 지양&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;b&gt;&amp;gt; 최종 논의 결과 : Service layer에 비즈니스 로직별 추가 검증 로직 추가&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;3. 결과&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;개선사항&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;#1 DB 기반 검증 추가&lt;/blockquote&gt;
&lt;pre id=&quot;code_1757067939248&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 예시: 게시글 수정 시 선행 검증 추가
PostResponseDto post = postMapper.findById(postId);
if (!post.getUserId().equals(authenticatedUserId)) {
    throw new AccessDeniedException(&quot;권한 없음&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;* AccessDeniedException를 서비스 레이어에서 throw하여 ControllerAdvice가 잡아 공통 403 error로 클라이언트에 응답&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;테스트&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# 사내 fiddler debugging, &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;BurpSuite &lt;/span&gt;테스트시&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;color: #333333; text-align: start; border-collapse: collapse; width: 100%; height: 63px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-start=&quot;1585&quot; data-end=&quot;1798&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 17.3256%;&quot;&gt;환경&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 36.2791%;&quot;&gt;개선 전 파라미터 변조 공격&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 36.2791%;&quot;&gt;개선 후 파라미터 변조 공격&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 9.88372%;&quot;&gt;비고&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-start=&quot;1716&quot; data-end=&quot;1755&quot;&gt;
&lt;td style=&quot;height: 21px; width: 17.3256%;&quot; data-start=&quot;1716&quot; data-end=&quot;1726&quot; data-col-size=&quot;sm&quot;&gt;Staging&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 36.2791%;&quot; data-start=&quot;1726&quot; data-end=&quot;1735&quot; data-col-size=&quot;sm&quot;&gt;passed&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 36.2791%;&quot; data-start=&quot;1735&quot; data-end=&quot;1740&quot; data-col-size=&quot;sm&quot;&gt;denied&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 9.88372%;&quot; data-start=&quot;1740&quot; data-end=&quot;1746&quot; data-col-size=&quot;sm&quot;&gt;없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-start=&quot;1756&quot; data-end=&quot;1798&quot;&gt;
&lt;td style=&quot;height: 21px; width: 17.3256%;&quot; data-start=&quot;1756&quot; data-end=&quot;1769&quot; data-col-size=&quot;sm&quot;&gt;Production&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 36.2791%;&quot; data-start=&quot;1769&quot; data-end=&quot;1777&quot; data-col-size=&quot;sm&quot;&gt;passed&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 36.2791%;&quot; data-start=&quot;1777&quot; data-end=&quot;1782&quot; data-col-size=&quot;sm&quot;&gt;denied&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 9.88372%;&quot; data-start=&quot;1782&quot; data-end=&quot;1789&quot; data-col-size=&quot;sm&quot;&gt;없음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# 이후 협력사 테스트 결과도 완료&lt;/b&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;4. 추후 이슈 및 대응&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;이슈 발생 사항&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;#1 JWT 보안 취약점 발견&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;기존 인증/인가를 위해 서버 session 대신 JWT token + sessionStorage 를 사용하였기에 HttpOnly인 쿠키가 아닌&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;sessionStorage로 브라우저 저장시&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;JWT token은 XSS 공격을 통해 탈취 가능성이 높은데&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;문제는 애플리케이션에 사용되는 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;JWT token decode시 PAYLOAD에 user primary key가 그대로 노출됨&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;808&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nEEcZ/btsQoOnnpoX/xsOTfgmqk9os1vn83xx63K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nEEcZ/btsQoOnnpoX/xsOTfgmqk9os1vn83xx63K/img.png&quot; data-alt=&quot;PAYLOAD에 pk 노출&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nEEcZ/btsQoOnnpoX/xsOTfgmqk9os1vn83xx63K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnEEcZ%2FbtsQoOnnpoX%2FxsOTfgmqk9os1vn83xx63K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;463&quot; height=&quot;315&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;808&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;PAYLOAD에 pk 노출&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757072349063&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (!post.getUserId().equals(authenticatedUserId))&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;span&gt;따라서 위와 같은 검증의 경우 HTTP 요청 파라미터에 authenticatedUserId을 탈취한 JWT PAYLOAD에 포함된 pk 값으로 변경할 경우 보안이 뚫리는 문제가 발생&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;@ 쉽게 단순히 PAYLOAD에 pk값을 지우면 되지 않나?&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;span&gt;&amp;gt; 현재 인증/인가 로직에서 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;JWT token&lt;/span&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;span&gt; claim을 사용하는 로직들을 전부 같이 수정해야하는데 이는 현실적으로 불가능&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;결론&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;span&gt;현재 악의적인 사용자가 JWT PAYLOAD로 정보를 알게 될 가능성이 높은 상황이지만 결국 서버가 발급하는 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;JWT 토큰의 서명과 인코딩 방식을 알지 못하면 변조 자체가 거의 불가능&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;(토큰 최초 발급시 대칭 HS256 &amp;rarr; &lt;b&gt;비대칭 RS256&lt;/b&gt; 으로 서명 전환, JWE를 사용한 암호화는 기존 시스템 제약으로 인해 보류)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&amp;gt; 서버 검증 로직을 기존 DB 레코드 기반에 더해 JWT Claim 기반 검증을 추가&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d; text-align: start;&quot;&gt;단, &lt;span style=&quot;text-align: start;&quot;&gt;JWT PAYLOAD 노출에 대한 보완이 없다면 이후 진행되는 모든 유지보수 과정에 반드시 이 점이 고려되어야 함&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;추가 고려 사항&lt;/b&gt;&lt;span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;#1 이전 논의처럼 검증 공통 로직이 많아질 경우 공통 인가용 AuthorizationService 도입 고려&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;* 다음 포스트에서 보안 취약점 대응 - 나머지 2, 3번 항목으로 이어짐&lt;/i&gt;&lt;/p&gt;</description>
      <category>Portfolio</category>
      <category>JWT</category>
      <category>변조</category>
      <category>보안취약점</category>
      <author>fadet</author>
      <guid isPermaLink="true">https://fadet-coding.tistory.com/98</guid>
      <comments>https://fadet-coding.tistory.com/98#entry98comment</comments>
      <pubDate>Fri, 5 Sep 2025 20:58:28 +0900</pubDate>
    </item>
    <item>
      <title>#1 CompletableFuture를 이용한 비동기화</title>
      <link>https://fadet-coding.tistory.com/97</link>
      <description>&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #555555; text-align: start;&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;* Portfolio 카테고리에 포스팅한 글들은 경력기술서나 포트폴리오에 첨부한 프로젝트 관련되어 작성한 내용임을 알립니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #555555; text-align: start;&quot;&gt;*&amp;nbsp; 내용에 대한 댓글은 언제나 환영입니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;1. 관련 프로젝트 및 업무 개요&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;* 사내 진행했던 프로젝트로 github repository나 실제 프로덕트 코드는 비공개이며 포스팅의 모든 사항은 공개 가능한 범위에서만 작성합니다.&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;프로젝트 및 업무 명(공개 가능)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사내 Spring Boot 백엔드 코드 수정 - FCM 알림 전송을 위한 비동기 API 개선&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;개발 환경&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;(공개 가능)&lt;/span&gt; &lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;Vue.js 2.6.x&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;intelliJ&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;JAVA 1.8 / Spring Boot 2.7.x / myBatis 2.3&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;Apache JMeter 5.2.1&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;2. 문제 분석 및 최초 Revision &lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;문제사항&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;다수의 특정 유저들을 대상으로 FCM API를 통해 모바일 알림이 가는 비즈니스 로직이 소요 시간이 예상치 상회&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;근거&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;# JMeter를 사용한 로컬 부하 테스트&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Number of Threads : 1000&lt;br /&gt;&lt;br /&gt;report&lt;br /&gt;평균 응답 시간: 60000~75000ms&lt;br /&gt;Throughput (TPS): 15~17&lt;br /&gt;Latency 분포: Percentile이 증가할수록 응답 시간이 길어짐&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;# 실제 Production 통신 테스트시 &lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;1000명 발송 기준 약 1분 이상 소요&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;분석&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;부하 테스트 및 실제 배포 환경 통신 테스트 결과를 토대로 기존 API 발송 로직 확인 결과 잘못된 Future 사용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;b&gt;논의 및 학습&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;* 작성된 코드는 비공개 프로덕트 코드가 아닌 전부 예시 코드임&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;// 기존 비동기 로직 작성 코드
String result1 = es.submit(task1).get();
String result2 = es.submit(task2).get();

// 위 코드와 완벽히 동치
Future&amp;lt;String&amp;gt; future1 = es.submit(task1);
String result1 = future1.get();

Future&amp;lt;String&amp;gt; future2 = es.submit(task2);
String result2 = future2.get();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;위 코드 블럭의 경우 얼핏 보면 비동기로 작성된 것처럼 보이지만 실제론 블로킹되어 동기적으로 작동&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;의도 : 메인 스레드는 task1, task2를 es(executorService) 스레드 풀에 존재하는 스레드 1, 스레드 2에 분배하여 비동기 처리&lt;br /&gt;&lt;br /&gt;실제 작동 :&lt;br /&gt;1 메인 스레드는 task1 submit 후 작업 종료 후 &lt;b&gt;결과 result1을 기다리므로 블로킹&lt;/b&gt; 됨(task1의 실행 시간 : a)&lt;br /&gt;2 메인 스레드는 result1 return 이후 마찬가지로 task2를 기다리므로 블로킹 됨(task2의 실행 시간 : b)&lt;br /&gt;실제 결과 : 메인 스레드 teminated까지 총 소요 시간 a + b 소요&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;&amp;gt;&amp;gt; CompletableFuture로 개선할 경우 이후 코드 수정이 존재하더라도 위와 같은 코드 가독성으로 인한 블로킹 문제가 생기지 않음&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;&lt;br /&gt;3. 결과&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;개선사항&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;* 작성된 코드는 비공개 프로덕트 코드가 아닌 전부 예시 코드임&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;CompletableFuture&lt;br /&gt;1.&amp;nbsp;future.get() 등 즉시 블로킹 로직 개선 가능&lt;br /&gt;2. 콜백 체이닝 사용 가능&lt;br /&gt;3. 예외처리 단순화&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;* 아래 예시 코드는 task를 1000 &amp;gt; 2로 줄여서 작성&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;List&amp;lt;CompletableFuture&amp;lt;String&amp;gt;&amp;gt; futures = List.of(
                CompletableFuture.supplyAsync(() -&amp;gt; task1(), es),
                CompletableFuture.supplyAsync(() -&amp;gt; task2(), es)
        );

// 모든 작업이 끝날 때까지 대기
CompletableFuture&amp;lt;Void&amp;gt; all = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));

// 결과 수집
List&amp;lt;String&amp;gt; results = all.thenApply(v -&amp;gt; futures.stream()
                .map(CompletableFuture::join)
                .toList()
).join();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드와 동일하게 FCM API 발송 부분에 대해&lt;b&gt;1 allOf를 사용하여 future.get() 블로킹 개선 2 supplyAsync, thenApply 등 콜백 체이닝을 통한 가독성 개선 진행&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;테스트&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; letter-spacing: 0px;&quot;&gt;# JMeter를 사용한 로컬 부하 테스트시&lt;/span&gt;&lt;/p&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;평균 응답 시간: 3000ms&lt;br /&gt;Throughput (TPS): 300&amp;nbsp;&lt;br /&gt;Latency 분포: Tail Latency까지 값이 거의 일정&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;# 실제 Production 통신 테스트시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;1000명 발송 기준 약 1분 이상 소요 &amp;gt; 약 5초 소요&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 68.2558%;&quot; border=&quot;1&quot; data-end=&quot;1798&quot; data-start=&quot;1585&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;환경&lt;/td&gt;
&lt;td style=&quot;width: 18.721%;&quot;&gt;개선 전 평균 응답 시간&lt;/td&gt;
&lt;td style=&quot;width: 18.8372%;&quot;&gt;개선 후 평균 응답 시간&lt;/td&gt;
&lt;td style=&quot;width: 7.5581%;&quot;&gt;TPS&lt;/td&gt;
&lt;td style=&quot;width: 9.76741%;&quot;&gt;Latency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1755&quot; data-start=&quot;1716&quot;&gt;
&lt;td style=&quot;width: 13.1395%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1726&quot; data-start=&quot;1716&quot;&gt;Staging&lt;/td&gt;
&lt;td style=&quot;width: 18.721%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1735&quot; data-start=&quot;1726&quot;&gt;60~75초&lt;/td&gt;
&lt;td style=&quot;width: 18.8372%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1740&quot; data-start=&quot;1735&quot;&gt;3초&lt;/td&gt;
&lt;td style=&quot;width: 7.5581%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1746&quot; data-start=&quot;1740&quot;&gt;300&lt;/td&gt;
&lt;td style=&quot;width: 9.76741%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1755&quot; data-start=&quot;1746&quot;&gt;거의 일정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1798&quot; data-start=&quot;1756&quot;&gt;
&lt;td style=&quot;width: 13.1395%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1769&quot; data-start=&quot;1756&quot;&gt;Production&lt;/td&gt;
&lt;td style=&quot;width: 18.721%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1777&quot; data-start=&quot;1769&quot;&gt;1분 이상&lt;/td&gt;
&lt;td style=&quot;width: 18.8372%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1782&quot; data-start=&quot;1777&quot;&gt;5초&lt;/td&gt;
&lt;td style=&quot;width: 7.5581%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1789&quot; data-start=&quot;1782&quot;&gt;300+&lt;/td&gt;
&lt;td style=&quot;width: 9.76741%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1798&quot; data-start=&quot;1789&quot;&gt;거의 일정&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;4. 추후 이슈 및 대응&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;이슈 발생 사항&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;#1 &lt;span style=&quot;text-align: start;&quot;&gt;FCM 발송 후 admin에 success count 미스매칭 발생&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;- 임계 영역 설정을 위해 모니터락을 사용한 synchronized나 ReentrantLock 사용시 성능 하락 발생&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;gt;&amp;gt; &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;success count&lt;/span&gt; 관련 변수에 AtomicInteger 사용(Atomic변수는 CAS 기반)&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;추가 고려 사항&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;#1 ThreadLocal 고려&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;List&amp;lt;CompletableFuture&amp;lt;Void&amp;gt;&amp;gt; futures = users.stream()
        .map(user -&amp;gt; CompletableFuture.runAsync(() -&amp;gt; {
            threadLocal.set(&quot;trace-&quot; + UUID.randomUUID());
            System.out.printf(&quot;[%s] Send FCM to %s%n&quot;, threadLocal.get(), user);
            threadLocal.remove();
        }, es))
        .toList();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;gt;&amp;gt; 회의 결과 성능 하락 우려로 인해 적용되진 않음&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Portfolio</category>
      <category>completablefuture</category>
      <category>Future</category>
      <category>멀티스레드</category>
      <category>블로킹</category>
      <category>비동기</category>
      <author>fadet</author>
      <guid isPermaLink="true">https://fadet-coding.tistory.com/97</guid>
      <comments>https://fadet-coding.tistory.com/97#entry97comment</comments>
      <pubDate>Thu, 4 Sep 2025 22:12:58 +0900</pubDate>
    </item>
    <item>
      <title>안녕하세요?</title>
      <link>https://fadet-coding.tistory.com/96</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 글을 포스팅하고 반년이 한참 넘었네요 ㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘부터 포스팅할 글들은 포트폴리오에 첨부할 프로젝트 관련 주제들일거라 기존 작성했던 글들과는 성격이 엄청 다를 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신에 기존 글들에서 좀 이상한 부분이나 첨언할 부분이 있다면 수정하려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 지금보면 당장 삭제하고 싶은 포스팅도 많지만... 이런 시절이 있었지 하며 남겨두려 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런만큼 글 보시다가 이상한 내용 있으시면 바로 알려주세요!&lt;/p&gt;</description>
      <category>Fadet's box</category>
      <author>fadet</author>
      <guid isPermaLink="true">https://fadet-coding.tistory.com/96</guid>
      <comments>https://fadet-coding.tistory.com/96#entry96comment</comments>
      <pubDate>Sat, 30 Aug 2025 22:47:11 +0900</pubDate>
    </item>
    <item>
      <title>L5_클라이언트-서버 API 통신 과정(백엔드) _1 클라이언트/서버</title>
      <link>https://fadet-coding.tistory.com/94</link>
      <description>&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #555555; text-align: start;&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;*&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;이 포스트는 학습 과정에서 그 내용을 기록한 글이기에 부정확한 정보가 포함될 수 있습니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #555555; text-align: start;&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;따라서 해당 글은 참고용으로만 봐주시고 틀린 부분이 있다면 알려주시면 감사하겠습니다. 또한 학습이 진행됨에 따라 언제든지 글이 수정될 수 있는 점 참고해주세요.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #555555; text-align: start;&quot;&gt;* 비유는 언제나 원관념이 일정 부분 희생됩니다. 이를 감안하셔서 너무 비유에 매몰되지 마시고 처음 학습하신다면 스스로 정확한 개념을 따로 더 학습하시길 바랍니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style2&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;  이 글은 개발자들 간 API 통신에 대해 다루기에 기본적으로 개발자들을 위한 글이지만 개발에 입문하시는 분들이나 관심이 있으신 일반인분들도 이해하실 수 있게 풀어서 작성합니다. 중간중간 이해가 어려울 수 있는 부분들은 refer를 추가하므로 보시는데 큰 어려움은 없으실 겁니다.&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;안녕하세요? 블로그에 어떤걸 포스팅하는게 정확히 8개월만이네요 하하... 취업 준비하고 입사 후에 적응하느라 많이 바빴습니다...는 핑계겠죠?&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;아무튼 이번에 입사해서 일을 배우다보니 클라이언트 서버 API 통신에 대해 다시 정리해보는 시간을 갖게 됐고 블로그에 포스팅하기 좋을 것 같아서 이렇게 글을 작성하게 됩니다. 아무래도 제가 백엔드 개발자다 보니 백엔드 개발자의 입장에서 통신을 살펴 볼 것이기에 너무 자세하게 프론트엔드 측 지식을 다루진 않을 것이고 가볍게 읽기 좋은 포스팅이라고 생각하고 봐주세요.&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;글이 길어질 것 같아서 시리즈로 포스팅하겠습니다. 이 글에서 다룰 첫번째는 Client-Server 모델 구조입니다.&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;# 클라이언트-서버 모델&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트와 서버로 흔히 알려진 &lt;span&gt;Client-Server &lt;/span&gt;모델&lt;span&gt;(&lt;/span&gt;이후 &lt;span&gt;C/S &lt;/span&gt;모델로 줄이겠습니다&lt;span&gt;)를&lt;/span&gt;&amp;nbsp;한 마디로 정리하면 &lt;b&gt;두 개의 컴퓨터가 서로 통신하는 방식 중 하나&lt;/b&gt;라고 말할 수 있을 겁니다&lt;span&gt;. &lt;/span&gt;두 개의 컴퓨터가 서로 통신하는 방식에는 여러 가지가 있습니다&lt;span&gt;. &lt;/span&gt;뒤에서 자세히 다룰 것이기에 간단히 꼽아보자면 다들 익숙하실 &lt;span&gt;P2P &lt;/span&gt;모델이 있습니다&lt;span&gt;. 더 나아가&lt;/span&gt;&amp;nbsp;우리가 대부분 사용할 어플리케이션의 통신에 있어서는 주로 &lt;span&gt;C/S &lt;/span&gt;모델을 채택한다고 생각하시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가게에서 물건을 주문하는 손님&lt;/b&gt;처럼 &lt;b&gt;네트워크로 정보를 요청하는 역할&lt;/b&gt;인 컴퓨터를 &lt;b&gt;클라이언트&lt;/b&gt;라 부릅니다&lt;span&gt;. &lt;/span&gt;그 예로 우리가 사용하는 크롬이나 엣지 등 브라우저가 있습니다&lt;span&gt;. &lt;/span&gt;사용자가 웹사이트를 방문할 때 서버에게 요청을 보내 원하는 정보&lt;span&gt;(&lt;/span&gt;웹 페이지 등&lt;span&gt;)&lt;/span&gt;을 가져옵니다&lt;span&gt;. &lt;/span&gt;&lt;b&gt;물건을 주문했으면 그 주문에 맞는 물건을 내주는 점원&lt;/b&gt;처럼 &lt;b&gt;요청한 정보를 처리하는 역할&lt;/b&gt;을 가진 컴퓨터를 &lt;b&gt;서버&lt;/b&gt;라 합니다&lt;span&gt;. &lt;/span&gt;이 서버는 워낙 평소에 추상적으로 사용되어 예시를 들기보단 뒤에서 더 자세히 설명하겠습니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 &lt;b&gt;클라이언트와 서버의 관계를 보통 네트워크 아키텍쳐 또는 분산 어플리케이션 구조&lt;/b&gt;라는 용어로 부르는데 우리는 C/S 모델을 이 중 &lt;b&gt;네트워크 아키텍쳐 중 하나&lt;/b&gt;로 간주하겠습니다&lt;span&gt;. &lt;b&gt;C/S &lt;/b&gt;&lt;/span&gt;&lt;b&gt;모델은 네트워크의 탄생 이후부터 아키텍처의 주류&lt;/b&gt;에 항상 있어 왔지만 정확한 &lt;span&gt;C/S &lt;/span&gt;모델의 이해를 위해선 네트워크 아키텍처의 변천사를 짧게 알아봐야합니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;# &lt;b&gt;클라이언트-서버 모델의 초창기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1960~70&lt;/span&gt;년대 당시에는 네트워크라는 개념도 희박했었기에 거의 모든 컴퓨팅 시스템은 &lt;b&gt;로컬에서 구축&lt;span&gt;, &lt;/span&gt;사용&lt;/b&gt;되었습니다&lt;span&gt;. &lt;/span&gt;그렇기에 중앙에 위치한 &lt;b&gt;메인프레임&lt;/b&gt;&lt;span&gt;(Mainframe) &lt;/span&gt;컴퓨터가 모든 컴퓨팅 자원을 제공하고&lt;span&gt;, &lt;/span&gt;사용자들은 이를 &lt;b&gt;터미널&lt;/b&gt;을 통해 접근했습니다&lt;span&gt;. &lt;/span&gt;이 방식을 &lt;b&gt;메인프레임&lt;span&gt;-&lt;/span&gt;터미널 모델&lt;/b&gt;이라 부릅니다&lt;span&gt;. &lt;/span&gt;이 모델에서 사용되는 &lt;b&gt;터미널은 정말 단순한 입출력 장치로&lt;/b&gt;서 작동했으며 거의 &lt;b&gt;모든 처리는 중앙에 위치한 메인프레임&lt;/b&gt;에서 이루어졌습니다&lt;span&gt;. &lt;/span&gt;그 예로는 &lt;span&gt;IBM &lt;/span&gt;메인프레임이 존재합니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;80&lt;/span&gt;년대 우리에게 익숙한 &lt;span&gt;PC&lt;/span&gt;가 도입되었고 기존의 단순한 입출력 역할만 했던 &lt;b&gt;터미널과는 다르게 중앙과 컴퓨팅 자원을 공유하고 연산이 충분히 가능&lt;/b&gt;했습니다&lt;span&gt;. &lt;/span&gt;따라서 우리에게 익숙한&lt;b&gt; &lt;span&gt;C/S &lt;/span&gt;모델은 이 때부터 주로 사용&lt;/b&gt;되었습니다&lt;span&gt;. &lt;/span&gt;물론 지금처럼 클라이언트인 브라우저가 할 수 있는 기능을 하기엔 이 때 &lt;span&gt;PC&lt;/span&gt;는 성능적으로 너무 안 좋았기 때문에 현 방식과는 큰 차이가 존재하지만 &lt;span&gt;C/S&lt;/span&gt;의 기본 개념은 동일했습니다&lt;span&gt;. &lt;/span&gt;이 때의 &lt;span&gt;C/S &lt;/span&gt;모델은 클라이언트에서 직접 DB에 접근하는 경우가 많았고 이를&amp;nbsp;&lt;b&gt;&lt;span&gt;2-&lt;/span&gt;티어&lt;span&gt;(2-Tier) &lt;/span&gt;아키텍처&lt;/b&gt;라고도 부릅니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 &lt;span&gt;90&lt;/span&gt;년대에 들어서 중앙의 컴퓨터가 너무 많은 부하를 받고 비용이 증가하자&lt;b&gt; &lt;span&gt;P2P (Peer-to-Peer) &lt;/span&gt;아키텍처&lt;/b&gt;가 등장했습니다&lt;span&gt;. P2P&lt;/span&gt;를 간단하게 소개하면 &lt;b&gt;네트워크 상의 컴퓨터들이 서버와 클라이언트 구분 없이 모두 대등한 지위에서 데이터를 주고받는 방식&lt;/b&gt;인데 이 방식에선 각 컴퓨터는 다른 컴퓨터와 데이터를 직접 공유할 수 있는 권한을 가집니다&lt;span&gt;. &lt;/span&gt;대표적으로 우리가 아는 웹하드&lt;span&gt;, &lt;/span&gt;토렌트 같은 파일 공유 프로그램이 이 방식입니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;P2P &lt;/span&gt;아키텍처는 물론 각 컴퓨터들의 자원을 공유시켜 효율적인 비용 관리에서 그 강점이 존재했지만 네트워크 애플리케이션의 복잡성이 너무 증가하고 사용자들의 요청이 엄청나게 늘어난 환경에선 사용하기 매우 어려웠습니다&lt;span&gt;. &lt;/span&gt;그래서 등장한 것이 &lt;u&gt;&lt;b&gt;&lt;span&gt;3-&lt;/span&gt;티어&lt;span&gt;(3-Tier) &lt;/span&gt;아키텍처&lt;/b&gt;&lt;/u&gt;입니다&lt;span&gt;. &lt;/span&gt;이 아키텍처는 크게 &lt;b&gt;&lt;span&gt;프레젠테이션 레이어&lt;/span&gt;&lt;/b&gt;&lt;span&gt;(UI), &lt;/span&gt;&lt;b&gt;&lt;span&gt;비즈니스 로직 레이어&lt;/span&gt;&lt;/b&gt;&lt;span&gt;, &lt;/span&gt;&lt;b&gt;&lt;span&gt;데이터 레이어&lt;/span&gt;&lt;/b&gt;로 나뉘는데 개발자들 입장에선 &lt;span&gt;&amp;lsquo;&lt;/span&gt;어&lt;span&gt;? &lt;/span&gt;지금 내가 접하고 있는 모델이 이건데&lt;span&gt;?&amp;rsquo;&lt;/span&gt;라고 생각하실겁니다&lt;span&gt;. 정확합니다&lt;/span&gt;&lt;span&gt;! &lt;/span&gt;현대 웹 어플리케이션의 대부분은 &lt;span&gt;C/S &lt;/span&gt;모델이라 통용되지만 &lt;b&gt;정확히는 이&lt;span&gt; 3-&lt;/span&gt;티어&lt;span&gt;(3-Tier) &lt;/span&gt;아키텍처라고 부르는게 맞습니다&lt;/b&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1125&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmTKKS/btsKwscFalg/D7IoE5V2mDsMyXTix3PKS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmTKKS/btsKwscFalg/D7IoE5V2mDsMyXTix3PKS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmTKKS/btsKwscFalg/D7IoE5V2mDsMyXTix3PKS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmTKKS%2FbtsKwscFalg%2FD7IoE5V2mDsMyXTix3PKS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;1125&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1125&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;#&lt;span&gt; 3-tier의 등장 이후 &lt;/span&gt;클라이언트-서버 모델&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 &lt;span&gt;3&lt;/span&gt;티어의 등장 이후 생긴 모든 네트워크 아키텍처는 어떻게 보면 이 &lt;span&gt;3&lt;/span&gt;티어&lt;span&gt; C/S &lt;/span&gt;모델의 단점을 보완하기 위해 생겼다고 해도 무방합니다&lt;span&gt;. 2000&lt;/span&gt;년대 들어서 등장한 &lt;b&gt;서비스 지향 아키텍처&lt;span&gt;(SOA, Service-Oriented Architecture)&lt;/span&gt;&lt;/b&gt;는 네트워크 모델이지만 그보단 어플리케이션 통신 방식이라고 이해하는 것으로 생각하는 것이 편합니다&lt;span&gt;. SOA&lt;/span&gt;는 &lt;b&gt;서로 다른 시스템들이 독립적인 서비스로 개발되고 제공되며&lt;span&gt;, &lt;/span&gt;이러한 서비스들이 네트워크를 통해 서로 표준화된 인터페이스로 통신할 수 있도록 설계된 아키텍처&lt;/b&gt;입니다&lt;span&gt;. 일반 사용자 입장에서 딱 알아들을만한&lt;/span&gt;&amp;nbsp;예시가 없어 부연 설명을 더 하자면 &lt;b&gt;&lt;span&gt;SOA&lt;/span&gt;는 재사용성에 초점을 맞춰 &lt;span&gt;SOAP&lt;/span&gt;이나 &lt;span&gt;REST&lt;/span&gt;같은 &lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;인터넷 데이터 교환 메커니즘을 &lt;span&gt;API&lt;/span&gt;로 구현하는 등의 설계 방식&lt;/b&gt;이라고 보시면 됩니다&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SOA&lt;span style=&quot;color: #333333;&quot;&gt;는 이후 &lt;span&gt;2010&lt;/span&gt;년대에 대두된 &lt;/span&gt;&lt;b&gt;마이크로서비스 아키텍처&lt;span&gt;(MSA, Microservices Architecture)&lt;/span&gt;&lt;/b&gt;와 비교해서 이해하면 편한데 &lt;b&gt;&lt;span&gt;MSA&lt;/span&gt;란 하나의 어플리케이션에 존재하는 결제&lt;span&gt;, &lt;/span&gt;인증&lt;span&gt;, &lt;/span&gt;유저관리 등 각 주요 기능들을 하나의 모듈별로 묶어 각 모듈은 독립적으로도 개발&lt;span&gt;, &lt;/span&gt;배포&lt;span&gt;, &lt;/span&gt;확장이 가능하며 이 모듈들이 연결되어 하나의 어플리케이션을 이루도록 하는 설계 방식&lt;/b&gt;입니다&lt;span&gt;. &lt;/span&gt;모듈화라는 관점에서 &lt;span&gt;Docker &lt;/span&gt;등 컨테이너 기술과 궁합이 잘 맞아 보통은 결합되어 자주 사용됩니다&lt;span&gt;. &lt;/span&gt;여기서 &lt;b&gt;&lt;span&gt;SOA&lt;/span&gt;와 &lt;span&gt;MSA&lt;/span&gt;는 각 기능을 분리한다는 공통점이 존재&lt;/b&gt;하여 헷갈릴 수 있지만 &lt;b&gt;&lt;span&gt;SOA&lt;/span&gt;는 서비스의 재사용성을 최우선하여 공통 기능을 분리한다는 개념으로 끝이지만 &lt;span&gt;MSA&lt;/span&gt;는 각 기능의 모듈화를 통해 서비스 간의 결합도를 낮추어 확장에 더욱 유리하도록 설계&lt;/b&gt;한다는 개념입니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 얘기해서 만약 &lt;span&gt;A&lt;/span&gt;라는 어플리케이션이 제공하는 기능에 채팅&lt;span&gt;, &lt;/span&gt;인증&lt;span&gt;, &lt;/span&gt;유저 관리 세 가지가 존재한다면&lt;b&gt;&lt;span&gt; SOA &lt;/span&gt;관점에선 주로 웹에서 공통적으로 사용되는 인증과 유저 관리 기능을 통합하여 다른 어플리케이션을 사용하더라도 이 통합된 기능을 사용할 수 있어 비용 절감에 큰 이득&lt;/b&gt;을 갖지만 &lt;b&gt;인증과 유저 관리 기능의 서비스 결합도는 증가&lt;/b&gt;합니다&lt;span&gt;. &lt;/span&gt;이를 &lt;b&gt;&lt;span&gt;MSA&lt;/span&gt;의 관점에서 설계한다면 채팅&lt;span&gt;, &lt;/span&gt;인증&lt;span&gt;, &lt;/span&gt;유저 관리 이 세 가지 기능 모두 독립적인 모듈로 개발하여 이후&lt;span&gt; A&lt;/span&gt;라는 어플리케이션에서 더 이상 유저 관리라는 기능을 사용하지 않게 변경합니다. 비교적 작은 서비스라면 오히려 비용적으로 마이너스가 될 수도 있지만 서비스가 커질수록 서비스간 결합도가 낮아 지고 비용 절감에 오히려 더 유리해지&lt;/b&gt;므로 이 점에서 SOA와 차이가 존재합니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지&lt;span&gt; C/S &lt;/span&gt;모델의 변화 과정을 짧게 살펴봤는데 이를 한 줄로 정리하면 &lt;b&gt;&lt;u&gt;대부분의 어플리케이션 구조는 이&lt;/u&gt; &lt;span&gt;3-Tier&lt;/span&gt;를 기본&lt;/b&gt;으로 설계되며 빅테크나 스타트업 등 &lt;b&gt;혁신을 추구하는 기업들은 여기서 더 나아가 &lt;span&gt;SOA, MSA&lt;/span&gt;같은 설계 방식을 결합&lt;/b&gt;한다고 생각하면 됩니다&lt;span&gt;. &lt;/span&gt;최근 많이 들리는 클라우드&lt;span&gt;, &lt;/span&gt;엣지 컴퓨팅 및 서버리스 아키텍쳐 같은 용어들도 물론 중요하지만 우리가 다루는 줄기에선 설명할 필요 없을 것 같습니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;# 클라이언트&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글의 초입에 클라이언트와 서버가 무엇인지에 대해 짧게 소개했었는데 둘의 통신 방식을 이해하는데 있어 좀 더 클라이언트와 서버 각각에 대해서 소개하는 것이 좋겠습니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클라이언트&lt;span&gt;(Client)&lt;/span&gt;는 개발 영역에서도 영단어의 뜻 그대로 고객&lt;span&gt;, &lt;/span&gt;의뢰인&lt;span&gt;, &lt;/span&gt;손님&lt;/b&gt;이라고 이해할 수 있습니다&lt;span&gt;. &lt;/span&gt;사실 일반인에게 가장 익숙한 클라이언트 개념은 &lt;b&gt;앱 클라이언트&lt;/b&gt;입니다&lt;span&gt;. &lt;/span&gt;대부분이 스마트폰을 사용하며 스마트폰에 어플리케이션을 설치하여 사용하는데 여기서 사용하는 어플이 앱 클라이언트라고 보시면 됩니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 개발자에게 클라이언트란 &lt;b&gt;네트워크 아키텍처에서 서버&lt;span&gt;(Server)&lt;/span&gt;에 요청을 보내고&lt;span&gt;, &lt;/span&gt;그 요청에 대한 응답을 받는 역할을 담당하는 컴퓨터나 프로그램&lt;/b&gt;입니다&lt;span&gt;. &lt;/span&gt;처음 설명했던 터미널도 어떻게 보면 &lt;span&gt;&amp;lsquo;&lt;/span&gt;기능이 매우 제한된&lt;span&gt;&amp;rsquo; &lt;/span&gt;클라이언트로도 볼 수 있겠죠&lt;span&gt;. &lt;/span&gt;특히나 웹 개발자들에게 클라이언트란 웹 클라이언트일 가능성이 높습니다&lt;span&gt;. &lt;/span&gt;이 클라이언트란 개념은 시간이 지나며 변화해왔기에 여러 사람에게 다른 의미로 받아들여집니다&lt;span&gt;. &lt;/span&gt;그렇기에 이에 대해 좀 더 잘 알기위해서 클라이언트의 변천사를 짧게 소개하겠습니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;#&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;클라이언트의 변천사&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;앞서 소개했듯 &lt;span&gt;60~70&lt;/span&gt;년대의 클라이언트는 터미널 형식으로 존재했습니다&lt;span&gt;. &lt;/span&gt;하지만 사실상 &lt;b&gt;터미널은 클라이언트라기 보단 우리가 사용하는 키보드나 마우스 같은 입력 장치&lt;/b&gt;에 더 가까웠습니다&lt;span&gt;. 80&lt;/span&gt;년대 들어 &lt;span&gt;PC&lt;/span&gt;가 등장했고 본격적으로 클라이언트라고 부를 수 있는 &lt;b&gt;분산 클라이언트&lt;/b&gt;&lt;span&gt;&lt;b&gt;(Distributed Client)&lt;/b&gt; &lt;/span&gt;형태로 나타났습니다&lt;span&gt;. &lt;/span&gt;터미널처럼 단순 서버에 신호만 보내는 것이 아닌&lt;b&gt; 클라이언트는 스스로 로컬에서 일부 데이터를 처리하고 계산할 수 있는 능력&lt;/b&gt;을 갖추게 되었습니다&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 등장한 것이 &lt;b&gt;&lt;span&gt;Fat(Thick) &lt;/span&gt;클라이언트&lt;/b&gt;입니다&lt;span&gt;. &lt;/span&gt;대표적으로 &lt;span&gt;MS office&lt;/span&gt;나 패키지 게임이 존재합니다&lt;span&gt;. &lt;/span&gt;이 팻 클라이언트는 &lt;span&gt;PC&lt;/span&gt;의 등장으로&lt;b&gt; 클라이언트 자체로도 충분히 많은 기능을 가지게 되었고 서버에 연산을 요청할 필요 없이 스스로도 사용자가 원하는 기능을 제공&lt;/b&gt;할 수 있었습니다&lt;span&gt;. &lt;/span&gt;이러한 팻 클라이언트는 서버에 요청할 일이 아예 없는 경우도 있었으니 네트워크 의존성은 매우 낮았다고 할 수 있겠죠&lt;span&gt;. &lt;/span&gt;하지만 &lt;b&gt;사용자의 &lt;span&gt;PC &lt;/span&gt;환경이 성능을 좌우했고 네트워크가 없다면 &lt;span&gt;SW &lt;/span&gt;업데이트에 있어서 어려움&lt;/b&gt;이 있었다는 단점이 존재했습니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이런 단점들이 있었기에 Fat 클라이언트는 사용자 입장에서 무겁게 느껴질만 했었고 그래서 등장한 것이 &lt;/span&gt;&lt;b&gt;&lt;span&gt;Thin&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;클라이언트&lt;/b&gt;입니다&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;클라이언트가 하는 역할은 터미널처럼 단순 요청은 아니나 화면 출력처럼 단순하고 대부분의 데이터 처리&lt;span&gt;/&lt;/span&gt;비즈니스 로직 수행은 서버에서 이루어진다는 게 가장 큰 특징&lt;/b&gt;입니다&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;현재도 사용되는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;HP&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;씬 클라이언트나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;Google Chrome OS(&lt;/span&gt;크롬 브라우저 아님&lt;span&gt;)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;등이 있습니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이후&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;00&lt;/span&gt;년대에 들어 이 씬 클라이언트를 보완하기 위해 나타난 것이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span&gt;Rich&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;클라이언트&lt;/b&gt;입니다&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;사실 리치 클라이언트의 개념은 씬 클라이언트와 비슷합니다&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;하지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span&gt;PC&lt;/span&gt;의 보급화와 어플리케이션 기능의 진화로 클라이언트에 기대되는 기능이 단순 화면 출력 이상&lt;/b&gt;으로 많아졌습니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어찌보면 리치 클라이언트는 팻 클라이언트에 네트워크 연결이 된 것으로 이해될 수 있는데 단순히 생각하면 맞을 수도 있는 설명이지만 두 클라이언트는 그 개념이 완전히 다릅니다&lt;span&gt;. &lt;/span&gt;&lt;b&gt;팻 클라이언트의 경우 서버는 단순히 &lt;span&gt;DB&lt;/span&gt;처럼 데이터만 제공할 뿐 대부분의 기능은 클라이언트가 담당&lt;/b&gt;합니다&lt;span&gt;. C/S &lt;/span&gt;모델이 대중화되기 이전이므로 서버와의 연결이 아예 필요 없는 경우도 많았습니다&lt;span&gt;. &lt;/span&gt;대표적으로&lt;span&gt; Ms office&lt;/span&gt;를 떠올리시면 쉬울겁니다&lt;span&gt;. &lt;/span&gt;하지만 &lt;b&gt;리치 클라이언트는 클라이언트도 물론 로컬에서 많은 작업들이 수행되지만 기본적으로 그 작업들은 서버에 요청할 데이터를 가공하고 서버가 응답한 데이터를 렌더링하는 작업&lt;/b&gt;이 주가 됩니다&lt;span&gt;.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;이 리치 클라이언트의 대표적인 예시가 엣지나 크롬 같은 브라우저 기반&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;웹 클라이언트&lt;/b&gt;입니다&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;대표적으로 웹 브라우저가 있습니다&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이 때 지금도 많이 사용되는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span&gt;&amp;lsquo;&lt;/span&gt;클라이언트가 서버로 요청&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;서버가 요청한 데이터를 처리&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;클라이언트가 응답된 데이터를 바탕으로 렌더링&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;&amp;rsquo;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;프로세스가 대중화되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이후 2010&lt;/span&gt;년대 우리 생활에 스마트폰이 너무나 익숙해질 때 같이 등장한 것이&lt;b&gt; 모바일 클라이언트&lt;/b&gt;입니다&lt;span&gt;. &lt;/span&gt;따로 설명할 필요가 없을 정도로 우린 이 구조를 너무 잘 압니다만 그래도 정리하자면&lt;b&gt; 스마트폰이라는 모바일 기기에 &lt;span&gt;iOS, Android &lt;/span&gt;같은 운영체제를 설치한 후 모바일 네트워크&lt;span&gt;(3G, Wifi)&lt;/span&gt;를 통해 서버와 상호작용하는 구조&lt;/b&gt;를 갖습니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;#&lt;span&gt;&lt;span&gt;&lt;span&gt; 웹 클라이언트의 &lt;/span&gt;&lt;/span&gt;렌더링 방식의 진화&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 모바일의 경우 우리가 잘 알지만 사실 모바일만큼이나 웹 환경도 크게 발달했습니다&lt;span&gt;. &lt;/span&gt;그 과정에서 기존의 클라이언트는 사용자 경험에 있어서 분명히 한계가 존재했고 그를 위해 등장한 것이 바로&lt;b&gt; &lt;span&gt;SPA, Single Page Application&lt;/span&gt;&lt;/b&gt;입니다&lt;span&gt;. 아주 정확한 것은 아니지만 이해를 할 때 SPA도 웹 클라이언트의 범주 안에 있다고 생각하는 것이 편합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 클라이언트가 서버와 통신할 때마다 &lt;b&gt;보통은 서버에서 페이지를 불러와서 렌더링을 하는 과정이 일반적&lt;/b&gt;이었습니다&lt;span&gt;. &lt;/span&gt;그래서 보통 우리가 어떤 버튼을 눌러 서버에 정보를 요청하거나 한 페이지 내에서 다른 메뉴로 이동하는 과정에서 대부분 페이지가 깜빡이며 기존의 페이지가 사라지고 새로운 페이지가 나타나는 경험을 했었습니다&lt;span&gt;. &lt;/span&gt;이렇게 &lt;b&gt;서버에서 새로 그려질 페이지 전체를 새로 불러와서 클라이언트가 그려주기&lt;/b&gt;만 하는 것을 &lt;b&gt;&lt;span&gt;SSR, Server Side Rendering&lt;/span&gt;&lt;/b&gt;이라고 합니다&lt;span&gt;. &lt;/span&gt;하지만 &lt;b&gt;&lt;span&gt;SSR&lt;/span&gt;은 요청마다 매번 서버에 그려질 페이지 정보를 가져와야 하므로 속도가 느린 편&lt;/b&gt;이었고 필수적으로 &lt;span&gt;html, css, js&lt;/span&gt;파일을 매번 로드하고 깜빡이는 과정이 필요했고 이를 앞서 사용자 경험에 한계가 있다고 표현한 것입니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;span&gt;SPA&lt;/span&gt;는 그런 단점을 개선하기 위해 페이지 &lt;b&gt;최초 접속시에 필요한 모든 &lt;span&gt;html, css, js &lt;/span&gt;파일을 불러오며 같은 페이지 내부에서 다른 메뉴로 이동할 경우 서버에서 그 페이지에 대한 정보를 매번 불러오는 것이 아닌 초기 로드된 파일을 바탕으로 클라이언트 자체에서 새로운 페이지를 그리게 됩니다&lt;span&gt;. &lt;/span&gt;&lt;/b&gt;속도면에서 초기에 로드할 수 없는 정보들&lt;span&gt;(&lt;/span&gt;예를 들어&lt;span&gt;, &lt;/span&gt;특정 인물의 사진처럼 유저가 선택해야지만 서버가 전달하는 정보&lt;span&gt;)&lt;/span&gt;의 경우에만 서버에 정보를 요청하는 통신&lt;span&gt;(&lt;/span&gt;주로 &lt;span&gt;AJAX)&lt;/span&gt;을 보내며 &lt;b&gt;이러한 렌더링 방식을&lt;span&gt; CSR, Client Side Rendering&lt;/span&gt;&lt;/b&gt;이라 부르며 일반적으로 &lt;b&gt;초기엔 모든 &lt;span&gt;SPA&lt;/span&gt;는 &lt;span&gt;CSR &lt;/span&gt;방식을 사용했다고 생각&lt;/b&gt;하시면 편합니다&lt;span&gt;. &lt;/span&gt;흔히 아는 &lt;span&gt;React, Vue, Angular &lt;/span&gt;등 웹 프레임워크들이 이에 사용됩니다&lt;span&gt;. 여기서 &lt;b&gt;SPA는 어플리케이션의 종류 중 하나, CSR은 그 어플리케이션의 렌더링 방식 중 하나&lt;/b&gt;로 이해하시면 됩니다. &lt;u&gt;&lt;b&gt;즉 SPA = CSR이 아니란 겁니다.&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 유저 사용 경험&lt;span&gt;(UX)&lt;/span&gt;을 크게 높일 수 있는&lt;span&gt; CSR &lt;/span&gt;방식 역시 단점이 많았습니다&lt;span&gt;. &lt;/span&gt;&lt;b&gt;초기에 많은 파일들을 로드하는 과정에서 속도가 느리며 서버 부하가 발생하고 현대 웹 서비스와 뗄 수 없는 검색 엔진 최적화&lt;span&gt;(SEO, Seach Engine Optimization)&lt;/span&gt;가 어렵습니다&lt;span&gt;. &lt;/span&gt;&lt;/b&gt;따라서 &lt;b&gt;빌드 시점에 모든 페이지가&lt;span&gt; html&lt;/span&gt;을 이용하여 정적으로 작성되며 이후 페이지별 &lt;span&gt;js&lt;/span&gt;가 로드되는 &lt;span&gt;SSG(Static Site Generation) &lt;/span&gt;방식&lt;/b&gt;이나 이전에 설명했던&lt;b&gt;&lt;span&gt; SSR &lt;/span&gt;방식을 함께 사용하는 웹서비스가 등장&lt;/b&gt;합니다&lt;span&gt;. &lt;/span&gt;대표적으로 많이 들어 보셨을 &lt;span&gt;Next.js&lt;/span&gt;나 &lt;span&gt;Nuxt.js &lt;/span&gt;같은 프레임워크가 대표적으로 이에 사용됩니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 살펴본 것처럼 모바일과 웹 클라이언트 둘다 기술의 발전과 같이 급속도로 발전했습니다&lt;span&gt;. &lt;/span&gt;하지만 기업에선 일부를 제외하곤 두 클라이언트 모두 사용자에게 만족스럽게 제공하는 것은 현실적으로 많이 어려웠습니다&lt;span&gt;. &lt;/span&gt;따라서 &lt;span&gt;2010&lt;/span&gt;년대 후반 &lt;b&gt;&lt;span&gt;PWA, Progressive Web Application&lt;/span&gt;&lt;/b&gt;가 등장하게 됩니다&lt;span&gt;. &lt;/span&gt;조금 다르지만 &lt;b&gt;쉽게 여러분이 아시는 모바일 환경에서 사용하던 네이티브 앱과 웹 앱의 장점을 합친 하이브리드 앱&lt;/b&gt;을 생각하시면 쉽습니다&lt;span&gt;. 예를 들어&lt;b&gt; PC에서 따로 내가 어플리케이션을 설치한 적이 없는데 실행하면 프로세스가 따로 생기는 어플들&lt;/b&gt;을 말합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;# 서버&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style5&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서버&lt;span&gt;(server)&lt;/span&gt;란 용어 자체는 정말 많은 분야에서 다양한 의미로 사용&lt;/b&gt;됩니다&lt;span&gt;. &lt;/span&gt;그렇기 때문에 앞서 살펴본 클라이언트도 있지만 특히나 &lt;b&gt;서버란 일반인과 개발자가 소통할 때 가장 혼선을 주는 단어&lt;/b&gt;이기도 합니다&lt;span&gt;. &lt;/span&gt;어떤 단어든 간에 시간이 흐르며 사용하는 환경이 바뀌며 뜻이 추가됩니다&lt;span&gt;. 그렇기에 서버라는 용어 자체는 시간이 흐르며 세대에 따라 받아들이는 의미가 조금씩 달라졌습니다. &lt;/span&gt;클라이언트도 앞서 살펴봤듯 계속 변화해 왔지만 사실 &lt;b&gt;서버는 클라이언트와 달리 일반 사용자의 입장에서 직접 다룰 수 없는 개념&lt;/b&gt;이기에 더욱 개변 현상이 심해진 것이라 생각합니다. 따라서 서버에 대해 더 잘 알려면 당연히 어떻게 서버가 변화해 왔는지 알 필요가 있다고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;#&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt; WAS&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 추상적인 서버의 개념에 대해 설명하겠습니다&lt;span&gt;. &lt;/span&gt;쉽게 서버가 하는 역할에 대해 얘기할텐데&lt;span&gt;, &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;초창기&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;중앙&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;서버는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;정적인&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;요청을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;받는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;웹&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;서버로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;충분&lt;/b&gt;했습니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;클라이언트는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;단순히&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;저장된&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;사진&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;동영상이나&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;업데이트에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;필요한&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;파일들만&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;요청&lt;/b&gt;했기&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;때문입니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하지만&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;웹이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;발전함에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;따라&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;서버는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;클라이언트의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;동적인&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;요청을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;처리하고&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;다양한&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;작업을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;수행&lt;/b&gt;해야만&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;했습니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;그래서&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;등장한&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;것이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;웹&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;어플리케이션&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;서버&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;(WAS, Web Application Server)&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;입니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;이름처럼&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;WAS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;요청을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;받으면&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;정해진&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;파일을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;응답하는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;웹&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;서버와는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;다르게&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;어플리케이션을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;사용하듯&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;요청에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;담긴&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;여러&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;파라미터에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;따라&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;연산을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;진행하여&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;동적으로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;응답을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;생성한&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;뒤&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;전달&lt;/b&gt;합니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;개발자라면&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;Apache Tomcat&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;대표적으로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;아실겁니다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;사실 요즘 배포된 많은 서비스들은 요청을 &lt;span&gt;WAS&lt;/span&gt;에서 직접 받는 것이 아닌 중간에 웹 서버&lt;span&gt;, cdn &lt;/span&gt;등을 거치게 되고 이 과정에서 프록시라는 개념도 알 필요가 있는데 이를 설명하려면 너무 길어지기에 다음에 자세히 다루도록 하고 우리는 &lt;span&gt;WAS&lt;/span&gt;라는 개념이 등장했다 정도만 기억하고 넘어가면 됩니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;i&gt;&lt;span&gt;* 이 부분에 대한 더 자세한 설명은 &lt;a href=&quot;https://fadet-coding.tistory.com/34&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://fadet-coding.tistory.com/34&lt;/a&gt; 의 WAS 파트에 조금 더 자세히 있습니다.&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 &lt;b&gt;웹 서버와&lt;span&gt; WAS &lt;/span&gt;서버처럼 클라이언트의 요청을 받아서 응답을 주는 중앙 컴퓨팅 장치를 서버로 이해&lt;/b&gt;할 수 있습니다&lt;span&gt;. &lt;/span&gt;&lt;b&gt;일반인이 이해하는 서버의 의미는 보통 이 개념&lt;/b&gt;이라고 생각하시면 됩니다&lt;span&gt;. &lt;/span&gt;만약 게임이나 채팅을 하는데 버벅이면 &lt;span&gt;&amp;lsquo;&lt;/span&gt;아 서버 터졌나보네&lt;span&gt;&amp;hellip;&amp;rsquo;&lt;/span&gt;라고 할 때처럼 말입니다&lt;span&gt;. &lt;/span&gt;여기까지 알아두면 뒤에 소개할 &lt;span&gt;infrastructure&lt;/span&gt;로서 서버의 변천사를 이해하는데 무리가 없을 것입니다&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;#&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt; Server as InfraStructure&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 서버의 역할이 아닌 &lt;span&gt;infrastructure&lt;/span&gt;로서 서버에 대한 역사를 짚어보겠습니다&lt;span&gt;. &lt;/span&gt;&lt;b&gt;초창기의 서버는 메인프레임을 의미&lt;/b&gt;했습니다&lt;span&gt;. &lt;/span&gt;이 &lt;b&gt;메인프레임은 그 당시 컴퓨팅 기술의 집약체로 많은 연산이 필요한 대기업이나 정부 기관에서나 사용&lt;/b&gt;할 수 있었습니다&lt;span&gt;. &lt;/span&gt;그만큼 정말 &lt;b&gt;고비용&lt;span&gt;, &lt;/span&gt;고성능의 장비였고 그렇기에 유연성이 낮고 유지보수 비용&lt;/b&gt;이 엄청났습니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 &lt;span&gt;PC&lt;/span&gt;의 등장으로 일부의 전유물이었던 서버는 여러 기업들도 사용할 수 있게 되었습니다&lt;span&gt;. &lt;/span&gt;기업은 &lt;span style=&quot;background-color: #ffffff; color: #565656;&quot;&gt;&lt;b&gt;베어메탈&lt;span&gt;(Bare Metal)&lt;/span&gt;이라고 주로 불리는 물리적인 서버를 운용&lt;/b&gt;합니다&lt;span&gt;. &lt;/span&gt;&lt;b&gt;연산을 처리할 수 있고 클라이언트에게 응답하는데 특화된 고성능의 &lt;span&gt;PC&lt;/span&gt;들을 모아서 &lt;span&gt;IDC, &lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;Internet Data Center&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;를&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;구축&lt;/b&gt;하고&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;구축한&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; IDC&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;자신들의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;중앙&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;서버를&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;구동시켜&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;클라이언트에게&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;요청을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;받아&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;정보를&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;제공하거나&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;개인&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;SW&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;를&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;업데이트&lt;/b&gt;해줍니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;여기서&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;엔지니어들은&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;실제&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;IDC&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;구축된&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;서버실&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;환경&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;자체를&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;서버&lt;/b&gt;라&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;부릅니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;따라서&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; 여기서 등장한 서버의 의미는 &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;앞서&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;역할로서의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;서버와는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;개념이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;상당히&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;다릅니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;435&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GFwUG/btsKuHvKDKs/Wjt1cUNo0C6KQG8I7lSDqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GFwUG/btsKuHvKDKs/Wjt1cUNo0C6KQG8I7lSDqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GFwUG/btsKuHvKDKs/Wjt1cUNo0C6KQG8I7lSDqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGFwUG%2FbtsKuHvKDKs%2FWjt1cUNo0C6KQG8I7lSDqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;435&quot; height=&quot;486&quot; data-origin-width=&quot;435&quot; data-origin-height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;초기&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;IDC&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;직접&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하드웨어에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;실제&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;서버를&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;구축하여&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;사용&lt;/b&gt;하였습니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;실제&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;응답하는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;서버&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;SW&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;를&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;IDC&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;구축한&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; PC&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;직접&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;설치하고&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;관리&lt;/b&gt;했다고&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;보시면&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;됩니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;조금만&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;생각해봐도&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;방식은&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;한계가&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;분명합니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;정말&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;단적인&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;예로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;내&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;PC&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;인터넷&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;브라우저와&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;게임을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;동시에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;실행했을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;때&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;인터넷으로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;대용량&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;파일을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;받는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;것처럼&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;네트워크&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;자원&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;소비가&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;과도해지면&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;같이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;실행&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;중인&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;게임의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;핑이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;튀는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;현상&lt;/b&gt;을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;겪어보셨을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;겁니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;문제가&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;PC&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;아닌&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;서버실에서&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;발생한다면&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;어떨까요&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;425&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCxQ92/btsKuzkgCwc/Uy9WxZIFzXg96tELI5EI41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCxQ92/btsKuzkgCwc/Uy9WxZIFzXg96tELI5EI41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCxQ92/btsKuzkgCwc/Uy9WxZIFzXg96tELI5EI41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCxQ92%2FbtsKuzkgCwc%2FUy9WxZIFzXg96tELI5EI41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;425&quot; height=&quot;482&quot; data-origin-width=&quot;425&quot; data-origin-height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;위와&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;같은&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;문제점을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;해결하기&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;위해&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가상화&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;(Virtualized) &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;기술이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;도입&lt;/b&gt;됩니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;아래&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;그림처럼&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;기존에는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하나의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;물리&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하드웨어&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;위에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하나의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;OS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;설치되고&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;그&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;위에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;여러&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;WAS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;실행&lt;/b&gt;되었습니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;과정에서&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;아까의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;예시처럼&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하나의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;WAS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;과도한&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;자원이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;몰리면&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;다른&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;WAS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;영향이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;것이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;불가피하며&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하나의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;OS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;에서&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;여러&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;WAS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;동작하므로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;호환이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;되지&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;않는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;WAS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;사용하지&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;못하거나&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;다른&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;OS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;를&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;설치한&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;또다른&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하드웨어를&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;추가로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;구축해야&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;했습니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하지만&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가상화&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;기술을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;도입하여&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가상&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;머신이란&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;개념을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;도입하면&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;아까처럼&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;물리&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하드웨어&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;위에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;OS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;직접&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;설치되는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;것이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;아닌&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;Hypervisor&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;설치&lt;/b&gt;됩니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하이퍼바이저란&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가상화&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;계층을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;구현해주는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;SW&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;이며&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;쉽게&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하드웨어와&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가상&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;머신의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;중간&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;관리자&lt;/b&gt;라고&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;생각하시면&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;됩니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하이퍼바이저&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;위에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;아까처럼&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;WAS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;들이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;직접&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;설치되는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;것이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;아닌&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;여러&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가상&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;머신이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;설치&lt;/b&gt;됩니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;개별&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가상&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;머신은&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하나의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;물리&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하드웨어처럼&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;작동하며&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;각자의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;OS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;를&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;설치하기에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;호환성에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;있어서&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;엄청난&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;이점&lt;/b&gt;을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;얻게&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;됩니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가상화는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;여러&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;이점이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;있지만&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;기존의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;단점을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;대체하기엔&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;한계가&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;존재했습니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;호환성&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;측면에서&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;각자의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;OS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;를&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가지는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;것은&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;좋았지만&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;다들&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;아시듯&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;OS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;많은&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;자원이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;필요하기에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가상&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;머신의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;온전한&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;성능을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;사용하지&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;못하고&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;초기에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가상&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;머신별로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;실제&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하드웨어&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;자원을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;분할해줘야하므로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;갑자기&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;서비스&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;중인&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;한&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;영역을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;축소시키는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;등의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;일이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;발생할&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;때&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하나의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가상머신에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;분할된&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;자원이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;잉여가&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;되는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;등&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;각&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가상&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;머신별로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;유연하게&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;자원을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;분할하지&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;못합니다&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;또한&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; 논리적으로 구분해서 사용한다 하더라도 &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;결국&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하나의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;물리적인&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하드웨어에서&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;구동되는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;것은&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;동일하므로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;만약&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하나의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가상&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;머신&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;오류로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하드웨어에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;직접적인&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;영향이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;생겨&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;다운되는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;경우&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;나머지&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가상&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;머신들도&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;꺼지는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;대참사&lt;/b&gt;가&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;발생하게&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;됩니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/peTpa/btsKvLqopX3/JzkveL7Pb0kF1dRRHzZ2S1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/peTpa/btsKvLqopX3/JzkveL7Pb0kF1dRRHzZ2S1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/peTpa/btsKvLqopX3/JzkveL7Pb0kF1dRRHzZ2S1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpeTpa%2FbtsKvLqopX3%2FJzkveL7Pb0kF1dRRHzZ2S1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;418&quot; height=&quot;482&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;그래서&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;등장한&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;것이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;컨테이너&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;(Containerized) &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;기술&lt;/b&gt;입니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;아래&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;그림처럼&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;컨테이너&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;기술에선&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하나의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;물리적인&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하드웨어가&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;아니라&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;외부의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;인프라&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;대표적으로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;클라우드&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;를&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;대여하고&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;또&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;여러&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;컴퓨팅&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;시스템을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;사용하여&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하나의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;패키지처럼&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;구성&lt;/b&gt;할&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;수&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;있습니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;그렇기&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;때문에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;필요한&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;span&gt;OS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;따라&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;컴퓨팅&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;시스템을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;분리하여&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; 각자가&amp;nbsp;&lt;span&gt;OS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;를&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;공유함으로써&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;자원&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;활용을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;효율적&lt;/b&gt;으로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;할&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;수&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;있습니다&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;또한&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;하나의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;컨테이너는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;이미지와&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;레이어라는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;개념을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;사용하기에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;가상&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;머신처럼&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; OS&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;를&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;깔고&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;프로그램을&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;설치하는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;등&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;여러&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;설치&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;절차가&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;필요&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;없이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;정의&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;파일대로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;빌드하면&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;되므로&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;특정&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;서비스가&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;폐쇄되면&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;그냥&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;컨테이너를&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;없애고&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;다음에&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;다시&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;&lt;b&gt;빌드&lt;/b&gt;하는&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;비용이&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;엄청나게&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;줄어들게&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #4d5156;&quot;&gt;됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 각 컨&lt;b&gt;테이너들이 설치되는 클라우드 등 인프라 패키지들 자체를 서버&lt;/b&gt;라고도 부르곤 합니다&lt;span&gt;. &lt;/span&gt;&lt;b&gt;개발자들이 흔히 백 서버&lt;span&gt;, DB &lt;/span&gt;서버 등등으로 편하게 부르는 용어들은 사실 &lt;span&gt;WAS&lt;/span&gt;나 &lt;span&gt;DBMS&lt;/span&gt;가 설치된 클라우드 서버&lt;/b&gt;를 뜻한다고 보시면 됩니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;끝에 다룬 서버의 변천사는 사실 작성한 내용보다 훨씬 내용이 많고 자세히 다루면 웹이 발달하면서 서버에게 요구되는 스펙들이나 클라우드 컴퓨팅의 대두 등 수많은 토픽들을 다뤄야합니다만 너무 길어지기도 하고 서버를 이해하는 데 있어서는 이 정도의 지식만 있다면 충분하다 생각됩니다&lt;span&gt;. &lt;/span&gt;이 정도 다뤘다면 누군가 서버라는 단어를 사용했을 때 맥락에 따라 어떻게 해석할지에 도움이 되었으면 좋겠습니다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 포스트에선 클라이언트-서버 모델에 대해 다뤘습니다. 이정도 서버와 클라이언트에 대한 지식을 갖췄다면 다음 포스트를 이해하시는데 큰 문제가 없을겁니다. 그렇다면 다음 글에서 뵙겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Learning</category>
      <category>서버</category>
      <category>클라이언트</category>
      <category>클라이언트-서버</category>
      <author>fadet</author>
      <guid isPermaLink="true">https://fadet-coding.tistory.com/94</guid>
      <comments>https://fadet-coding.tistory.com/94#entry94comment</comments>
      <pubDate>Mon, 4 Nov 2024 15:21:27 +0900</pubDate>
    </item>
    <item>
      <title>P4_기존 프로젝트에 배포 자동화 구축하기(github actions)_2</title>
      <link>https://fadet-coding.tistory.com/93</link>
      <description>&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;*&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;이 포스트는 학습 과정에서 그 내용을 기록한 글이기에 부정확한 정보가 포함될 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;따라서 해당 글은 참고용으로만 봐주시고 틀린 부분이 있다면 알려주시면 감사하겠습니다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;❗ 글을 시작하기에 앞서 말씀드리자면 엄밀히 CI/CD와 배포 자동화는 다른 개념이지만 이 포스트에선 배포자동화를&lt;br /&gt;CI/CD로 부르겠습니다. 처음 공부할때 작성한 포스트라 이 부분은 추후 수정하겠습니다&lt;br /&gt;&lt;br /&gt;❗ 대상 독자 : CI/CD 파이프라인 구축에 입문하는 주니어 개발자&lt;br /&gt;&lt;br /&gt;❗ 이 글은 기존 프로젝트에 github actions를 이용한 CI/CD를 구축하는 내용을 메인으로 합니다. 따라서 독자분이 기존 프로젝트에 사용했던&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Git, Spring Boot, Docker, AWS&lt;/b&gt;에 대해 잘 모르신다면 검색을 해보시거나 아래 링크를 통해 ai에게 질문해 보시고 포스트를 보시는 것을 추천드립니다. 이 포스트에서 가장 중요하게 다뤄지는 github actions를 아예 모르신다면 refer에 추가해둔 생활코딩님의 영상을 보시는 것도 좋습니다,&lt;i&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/i&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style2&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이전 포스트는 제가 적용한 전체적인 파이프라인을 개괄적으로 다뤘습니다. 그리고 이번 포스트는 좀 더 프로세스를 단계별로 다뤄보겠습니다. 대신 글이 너무 길어지는 관계로 진행하며 툴에 대한 기본적인 설명이 필요하다면 각주로 대신할 테니 링크를 보시거나 위에서 말한 ai에게 질문을 해주시면 되겠습니다.&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;저번 포스트에서 다가올 미래를 생각하지 않았다는 말을 했었는데 아래 그림만 보셔도 대충 감이 오실 것이라 생각합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1855&quot; data-origin-height=&quot;741&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4eNNz/btsEhVGa0NO/14bQfCrZVhbYL4uhgQgoak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4eNNz/btsEhVGa0NO/14bQfCrZVhbYL4uhgQgoak/img.png&quot; data-alt=&quot;너무 반복하느라 커밋명을 정하기도 귀찮아서 숫자로 넘버링만 한 게 포인트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4eNNz/btsEhVGa0NO/14bQfCrZVhbYL4uhgQgoak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4eNNz%2FbtsEhVGa0NO%2F14bQfCrZVhbYL4uhgQgoak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;610&quot; height=&quot;244&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1855&quot; data-origin-height=&quot;741&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;너무 반복하느라 커밋명을 정하기도 귀찮아서 숫자로 넘버링만 한 게 포인트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: left;&quot;&gt;이 포스트는 practice로 따라하시기엔 코드도 없고 자세한 설명도 없습니다. 제가 학습하면서 느낀 건데 어떤 예제든지 그대로 따라 하려고 하면 아무 의미가 없는 데다 자기 프로젝트에 내용을 적용할 때 포스트 내용대로 해봤자 작동하지 않기에 시간을 써서 스스로 부딪혀보는 게 제일 중요하더라고요. 실제로 이번 내용도 포스트 하기 전에 위 그림처럼 actions만 몇 번을 반복했고 또 AWS 리눅스 cli로 계속 설정을 수정했었습니다. 그래서 이 포스트는 설정들을 하며 겪은 시행착오 대신&lt;/span&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;'본인 프로젝트에 CI/CD를 적용할 때 이런 방법도 있을 수 있구나'&lt;/b&gt;&lt;span style=&quot;color: #555555; text-align: left;&quot;&gt;&lt;span&gt; 에 포커스를 맞춰서 봐주시면 감사하겠습니다&lt;/span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;우선 이전 글에서 보셨던 그림을 다시 한번 보겠습니다. 그전에 말씀드릴게 이 프로세스는 제 프로젝트에 맞게 축약한 단계들도 있고 그 나름의 이유들도 후술하니 이걸 'CI/CD 파이프라인이라 부를 수 있어?'라는 생각은 속으로만 해주세요 ㅠㅠ&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQx898/btsEkRo9Tw6/kEYF9dkT0IlKhwkMRA6m00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQx898/btsEkRo9Tw6/kEYF9dkT0IlKhwkMRA6m00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQx898/btsEkRo9Tw6/kEYF9dkT0IlKhwkMRA6m00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQx898%2FbtsEkRo9Tw6%2FkEYF9dkT0IlKhwkMRA6m00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1600&quot; height=&quot;900&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;900&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 프로세스의 각 단계를 짚어볼건데 &lt;b&gt;'저는 이런 흐름으로 적용했습니다.'&lt;/b&gt;와&lt;b&gt; '적용 가능한 다른 방식과 툴들'&lt;/b&gt; 두가지를 중점적으로 서술하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;#1 IDE를 통해 코드 작성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 저는 주로 자바를 사용하기 때문에 ItelliJ를 사용했지만 VSCode를 사용해도 달라질 건 없습니다. ItelliJ가 워낙 git과 잘 연동되지만 VSCode도 익스텐션을 사용하면 그에 못지않게 편하더라고요. 제 수준에선 IDE는 크게 중요하진 않은 것 같습니다. 만약 도구를 바꿔 github에서 개발한 Atom을 써서 IDE까지 git과 아예 통합해 보는 것도 나쁘진 않을 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;#2 git에 코드 푸쉬&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 다른 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;SVN이나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Mercuria 등이 있긴 하지만 CI/CD 툴로 github actions를 사용하는 만큼 VCS로는 Git을 대체할 건 딱히 없습니다. 그나마 수정할 점이라면 현재 워크플로우에 모든 푸쉬시 actions에 요청을 보내도록 설정해서 만약 실무에서 여러 작업자들이 관리한다면 현재는 머지를 하든 리베이스를 하든 모두 요청이 가도록 되어있는데 트리거 될 브랜치도 분리하고 작업도 구분해줘야 할 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;#3 github actions에 빌드 및 배포 요청&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;# 3번 과정의 전체 흐름&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;기존의 빌드와 배포 프로세스를 한 번에 합쳐버린 만큼 해당 단계가 신경 쓸 것도, 알아야 할 것도, 보완해야 할 것도 가장 많습니다.&lt;/b&gt; 우선 해당 단계에서 아래와 같이 크게 세 단계로 작업이 진행되며&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;1. github에 push 된 커밋을 기반으로 github actions&lt;b&gt; queue에 등록&lt;/b&gt; &amp;gt; 2. 작성해 둔 main.yml대로 지정된 workflow&lt;b&gt; In progress&lt;/b&gt; &amp;gt; 3. EC2에 깔아 둔 runners가 빌드된 도커 파일을 받아 &lt;b&gt;docker-compose&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 딱 확실하게 구분되진 않지만 2단계는 빌드 3단계는 배포로 볼 수 있습니다. 이 과정에서 실행되는 작업을 조금 자세히 풀어 써보자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@ main.yml에 미리 빌드와 배포에 사용될 env(환경 변수)를 작성해 둡니다. 그리고 env로 사용될 github secret을 미리 발급받습니다. main.yml 전문은 &lt;a href=&quot;https://github.com/kth1017/project_GptApiPlusCi/blob/main/.github/workflows/main.yml&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/kth1017/project_GptApiPlusCi/blob/main/.github/workflows/main.yml&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@ 트리거 이후 수행될 job은 아래와 같습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;u&gt;&lt;b&gt;빌드(2)&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;1. github repository에서 checkout : repo에 커밋된 파일들을 actions에 사용하도록 checkout 합니다.&lt;br /&gt;2. docker build 수행 : 최종적으로 EC2에 도커로 배포할 예정이므로 이 단계에선 도커로 빌드합니다.&lt;br /&gt;3. (빌드 캐싱 작업) : 물론 해두면 속도 향상에 크게 도움이 되지만 입문하실 땐 여러 번 파일을 수정하실 텐데 캐시 때문에 작업이 더뎌질 수 있습니다.&lt;br /&gt;4.&amp;nbsp; ghcr(GitHub Container Registry)에 로그인 후 빌드 &amp;amp; 푸시 : docker hub 대신 git에서 제공하는 ghcr에 이미지를 푸시&lt;br /&gt;&lt;u&gt;&lt;b&gt;배포(3)&lt;br /&gt;&lt;/b&gt;&lt;/u&gt;1. ghcr에 로그인 : 이미지를 pull 하기 위해 env에 언급해둔 secret으로 ghcr에 로그인&lt;br /&gt;2. 도커 실행 : EC2에 깔아 둔 docker를 통해 docker-compose로 서비스 네트워크 배포&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 위의 작업에서 조금 부가 설명이 필요한 부분을 말해보자면 우선 &lt;b&gt;checkout, cache, build, login 등 job의 각 단계들은 uses 구문으로 사용되는데 이는 github에서 미리 만들어서 등록된 액션들을 사용&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;넘어가서 캐싱 작업을 선택으로 표시한 이유는 물론 작동 속도를 높이기 위해 캐싱을 해두는 것은 거의 필수긴 하지만 처음 이 부분을 배우고 적용하시는 분들은 코드를 여러 번 수정하고 적용해 보는 작업을 정말 여러 번 할 텐데 그 과정에서 캐시가 좀 학습자를 헤매게 만들 수도 있습니다. 우리가 IDE를 쓸 때 캐시 때문에 제대로 된 코드가 작동 안 할 때가 있잖아요? 마찬가지입니다. 근데 거기에다가 actions를 처음 접하신다면 더 크게 다가오겠죠. 그래서 이 캐싱 부분은 선택적으로 포함할지 고려하시면 되겠네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그다음 여기선 ghcr로 이미지를 푸시합니다. 우리가 보통 docker를 사용하면 이미지를 docker hub로 푸시하는데요. 이 단계에선 단지 저장소를 ghcr(GitHub Container Registry)로 대체한 겁니다. docker hub에 이미지를 푸시하도록 작성하셔도 결과는 동일합니다. 사용 정책이나 액세스 등 다른 이유들도 물론 있지만 ghcr을 사용하는 게 통합에 유리하다는 게 이렇게 작성한 가장 큰 이유입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 배포 작업은 미리 EC2에 gihub actions에서 제공하는 runners*를 이용해 진행합니다. 앞서 빌드 작업에도 runners가 사용되는데 앞서 사용되는 건 Github-Hosted Runners고 배포에 사용되는 건 Self-Hosted Runners입니다. Self-Hosted Runners의 경우 자체적으로 프로젝트 환경에 가상 머신을 설정하므로 우리는 Self-Hosted Runners를 github에서 생성해 두고 이를 EC2에서 실행해 배포를 진행합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;i&gt;* runners가 뭔지 모르신다면 &lt;a href=&quot;https://velog.io/@zuckerfrei/Github-Actions-1.-self-hosted-runner&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@zuckerfrei/Github-Actions-1.-self-hosted-runner&lt;/a&gt;를 참조&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;# 적용 가능할 수 있는 다른 사항&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;nbsp; 이전 포스트에서 설명했듯 빌드와 배포를 합친 이런 프로세스의 경우 CodeDeploy나 CodePipeline을 사용해도 되고 GitLab을 사용해도 됩니다. 또한 배우기 쉬운 CI툴인 jenkins나 travisCI에 배포 툴을 사용해서 책임을 분리해도 좋습니다. 하지만 저는 &lt;b&gt;통합과 접근성&lt;/b&gt; 면에서 이런 프로세스를 적용했습니다. 딱 봐도 엄청 간단하지 않나요? main.yml을 보시면 알겠지만 workflow도 정말 간략하게 줄여서 적용했기에 전체적인 흐름 역시 쉽게 보실 수 있으리라 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 제가 적용한 프로세스는 사실 기존 CI/CD 파이프라인을 압축해서 변형한 것이라 생각하시면 됩니다. 한마디로 일부 과정을 지키고 있지만 개선하고 확장할 점이 많다는 얘기죠. 크게 다음과 같은 점들이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;1. 테스트 통합 : 사실 워크플로우 과정 중 빌드 이전에 코드 테스트를 진행하는 &lt;b&gt;테스트 자동화 과정이 포함&lt;/b&gt;되어야만 합니다. 저 같은 경우엔 스프링 부트로 서버를 작성했으니 junit을 이용해 테스트 통합 과정을 진행했어야 맞죠. 하지만 제 경우 현재 테스트 코드를 수정하며 서버의 클래스 구조를 계속 고치고 있기에 테스트 코드에 변경이 많아서 캐시를 해도 이 과정에서 소모되는 시간이 큽니다. 따라서 제 경우 테스트는 jar 빌드 이전에 따로 수행하도록 해둬서 소위 말하는 테스트 통합 과정을 뺐습니다.&lt;br /&gt;&lt;br /&gt;2. 오토스케일링/무중단 배포 및 CDN 활용 : 보통 실무에서 큰 프로젝트에 CI/CD를 적용하면 반드시 로드밸런싱을 적용해서 무중단 배포를 하는 것이 일반적이며 클라우드 환경에서의 오토스케일링 설정 또한 필요합니다. 그리고 많은 이용자가 사용하는 서비스의 경우에 CDN을 사용하는 것이 매우 유리합니다. 하지만 제 경우 소규모 개인 프로젝트이며 사용자도 많지 않기에 해당 부분은 적용하지 않았습니다. 하지만 소규모 개인 프로젝트라 하더라도 무중단 배포 방식을 한 번쯤 알아보시는 것을 추천드립니다.&lt;/blockquote&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;i&gt;* 무중단 배포의 예시인 멀티 컨테이너 배포는 &lt;a href=&quot;https://codegear.tistory.com/91&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://codegear.tistory.com/91&lt;/a&gt;&amp;nbsp;참고&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;#4 배포&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 이번 프로젝트에서 배포하는 인스턴스는 AWS EC2고 OS는 linux(ubuntu)입니다만 클라우드를 사용하실 거라면 Azure나 GCP를 이용해 보셔도 좋을 것 같습니다.(온 프레미스 환경은 고려하지 않겠습니다.) 아니면 같은 AWS 내에 더 추상화를 해주는 AWS EB를 사용해 보시는 것도 좋을 것 같네요.(전 설정에 너무 오래 걸려서 EB는 하다가 포기했습니다만...) 배포는 위에서 일부 언급했지만 docker를 통해 이뤄졌습니다. 여기서 같은 VPC에 AWS RDS를 연결해서 DB로 사용합니다. 사실 로드밸런싱이나 오토스케일링을 고려해서 인스턴스를 두 개 이상 사용한다던지 하면 서브넷과 AZ도 고려해야 하지만 저는 그 정도까진 고려할 필요 없을 것 같았습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;#5 AWS SSM으로 환경 설정 및 모니터링&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- AWS SSM(SyStems Manager)은 AWS에서 제공하는 리소스 관리 및 모니터링, 자동화를 제공하는 도구로 쉽게 말해 인프라 환경 관리 툴입니다. SSM의 경우 EC2가 아닌 개인 온 프레미스 서버나 가상 머신들도 연동해서 사용할 수 있다고 하던데 사실 써보진 않아서 넘어가겠습니다. 제가 SSM을 쓴 가장 큰 이유는 이전 글에서 언급했던 것처럼 SSH 연결을 대체하기 위해서입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;EC2 서버에 기존에 접근하기 위해선 일반적으로 SSH(Secure SHell) 연결이 필요합니다. 이 때 맥의 경우 cmd로 직접 서버에 연결이 가능하지만 윈도우의 경우 putty라는 서드파티 툴을 사용해야 합니다. 게다가 OS 관계 없이 pem key를 받아서 이를 관리하는 것도 사실 불안한데 putty의 경우 심지어 이 키를 자체적으로 저장해둬야 합니다. 아무리 암호화 작업이 이루어져있어도 찝찝한건 어쩔 수 없습니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;저 같은 경우는 이 putty를 켜는 것도 귀찮아서 EC2에 jupyter notebook을 설치해 웹으로 EC2에 접근할 수 있게 해 뒀습니다만 이것 역시 인증서도 설정해야 하고 여러 가지 명령어도 추가로 쳐줘야 하는 것은 당연합니다. 그래서 &lt;b&gt;이런 번거로운 점들을 해결해 줄 수 있는 게 AWS SSM&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;SSM을 사용한다면 가장 좋은 점은&lt;b&gt; 애초에 인스턴스를 만들 때 pem key를 생성할 필요조차 없습니다. 단순히 IAM만 맞춰준다면 AWS 콘솔에서 바로 세션 관리자를 통해 EC2 서버에 접근&lt;/b&gt;할 수 있습니다. 또한 inventory에서 제 서버가 어떻게 가용되는지 모니터링도 하나의 대시보드로 할 수 있습니다. 이를 다른 도구로 대체한다고 한다면 SSM이 지원하는 기능이 엄청 다양하므로 이를 대체할 수 있다고 하기엔 목적에 따라 매번 달라지므로 애매합니다. 제 경우에 한해선 가장 큰 게 SSH 대체였으니 이것 대신 SSH를 그냥 사용하거나 접근용 IP를 설정해도 되긴 하겠네요.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;추후 필요하다면 제가 겪은 과정들을 자세히 풀어낼 수도 있겠지만 앞서 얘기했듯 굳이 포스트 할 필요가 있을까 싶어 일단은 접어두겠습니다. 만약 궁금한 점이 있으시다면 덧글로 남겨주세요.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;refer&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://codegear.tistory.com/84&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://codegear.tistory.com/84&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1706803083608&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;배포자동화(CI/CD) - Github Actions/Nuxtjs/Docker/EC2&quot; data-og-description=&quot;다음은 이 글의 유튜브 영상입니다. https://youtu.be/E3i9qt0SS-I 프로젝트를 진행할때 많은 시간을  들여야 하는 것 중에 하나가 바로 배포입니다. 형상관리(Git)에 커밋을 하고, 서버에 파일을 업로드 &quot; data-og-host=&quot;codegear.tistory.com&quot; data-og-source-url=&quot;https://codegear.tistory.com/84&quot; data-og-url=&quot;https://codegear.tistory.com/84&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/MEhmm/hyVfZcA2XG/m8Y3xKeObNEAOUWDC3Kjnk/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/dZsgao/hyVcb6So5E/KCWH9hIqUWOFuls0nazIik/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bjsktf/hyVgayqzVj/ZTste5nyKmFzhSjpoeyGGK/img.png?width=753&amp;amp;height=715&amp;amp;face=0_0_753_715&quot;&gt;&lt;a href=&quot;https://codegear.tistory.com/84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://codegear.tistory.com/84&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/MEhmm/hyVfZcA2XG/m8Y3xKeObNEAOUWDC3Kjnk/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/dZsgao/hyVcb6So5E/KCWH9hIqUWOFuls0nazIik/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bjsktf/hyVgayqzVj/ZTste5nyKmFzhSjpoeyGGK/img.png?width=753&amp;amp;height=715&amp;amp;face=0_0_753_715');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;배포자동화(CI/CD) - Github Actions/Nuxtjs/Docker/EC2&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;다음은 이 글의 유튜브 영상입니다. https://youtu.be/E3i9qt0SS-I 프로젝트를 진행할때 많은 시간을  들여야 하는 것 중에 하나가 바로 배포입니다. 형상관리(Git)에 커밋을 하고, 서버에 파일을 업로드&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;codegear.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;a href=&quot;https://velog.io/@zuckerfrei/Github-Actions-1.-self-hosted-runner&quot;&gt;https://velog.io/@zuckerfrei/Github-Actions-1.-self-hosted-runner&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1706803105474&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Github Actions - 1. self-hosted runner&quot; data-og-description=&quot;Github Actions의 runner 개념 및 self-hosted runner 설치 방법 정리&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@zuckerfrei/Github-Actions-1.-self-hosted-runner&quot; data-og-url=&quot;https://velog.io/@zuckerfrei/Github-Actions-1.-self-hosted-runner&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/kDo3p/hyVcbsexr1/SdkKl84bsjuJfsHR5FKQiK/img.png?width=304&amp;amp;height=327&amp;amp;face=0_0_304_327,https://scrap.kakaocdn.net/dn/eAAOy/hyVf4ZgPSQ/sgEXid8B3jX7b2V7zvQNYk/img.png?width=304&amp;amp;height=327&amp;amp;face=0_0_304_327,https://scrap.kakaocdn.net/dn/ieYk6/hyVf2f48j0/rrRvWLNXeBaDmsqOJ5HXK0/img.png?width=304&amp;amp;height=327&amp;amp;face=0_0_304_327&quot;&gt;&lt;a href=&quot;https://velog.io/@zuckerfrei/Github-Actions-1.-self-hosted-runner&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@zuckerfrei/Github-Actions-1.-self-hosted-runner&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/kDo3p/hyVcbsexr1/SdkKl84bsjuJfsHR5FKQiK/img.png?width=304&amp;amp;height=327&amp;amp;face=0_0_304_327,https://scrap.kakaocdn.net/dn/eAAOy/hyVf4ZgPSQ/sgEXid8B3jX7b2V7zvQNYk/img.png?width=304&amp;amp;height=327&amp;amp;face=0_0_304_327,https://scrap.kakaocdn.net/dn/ieYk6/hyVf2f48j0/rrRvWLNXeBaDmsqOJ5HXK0/img.png?width=304&amp;amp;height=327&amp;amp;face=0_0_304_327');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Github Actions - 1. self-hosted runner&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Github Actions의 runner 개념 및 self-hosted runner 설치 방법 정리&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=uBOdEEzjxzE&amp;amp;t=1102s&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=uBOdEEzjxzE&amp;amp;t=1102s&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=uBOdEEzjxzE&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/wBTtP/hyVb8WAjoo/iqJTp2b9Ju3iVkvPyQtSV1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/uBOdEEzjxzE&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Project</category>
      <category>AWS</category>
      <category>cd</category>
      <category>ci/cd</category>
      <category>docker</category>
      <category>github actions</category>
      <category>배포 자동화</category>
      <author>fadet</author>
      <guid isPermaLink="true">https://fadet-coding.tistory.com/93</guid>
      <comments>https://fadet-coding.tistory.com/93#entry93comment</comments>
      <pubDate>Fri, 2 Feb 2024 01:09:01 +0900</pubDate>
    </item>
    <item>
      <title>P4_기존 프로젝트에 배포 자동화 구축하기(github actions)_1</title>
      <link>https://fadet-coding.tistory.com/92</link>
      <description>&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;*&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;이 포스트는 학습 과정에서 그 내용을 기록한 글이기에 부정확한 정보가 포함될 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;따라서 해당 글은 참고용으로만 봐주시고 틀린 부분이 있다면 알려주시면 감사하겠습니다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;*&amp;nbsp; 2025.08.30 내용 수정 및 주석 추가&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;❗ 글을 시작하기에 앞서 말씀드리자면 엄밀히 CI/CD와 배포 자동화는 다른 개념이지만 이 포스트에선 배포자동화를 &lt;br /&gt;CI/CD로 부르겠습니다. 처음 공부할때 작성한 포스트라 이 부분은 추후 수정하겠습니다.&lt;br /&gt;&lt;br /&gt;❗ 대상 독자 : CI/CD 파이프라인 구축에 입문하는 주니어 개발자&lt;br /&gt;&lt;br /&gt;❗ 이 글은 기존 프로젝트에 github actions를 이용한 CI/CD를 구축하는 내용을 메인으로 합니다. 따라서 독자분이 기존 프로젝트에 사용했던 &lt;b&gt;Git, Docker, Travis CI, AWS&lt;/b&gt;에 대해서 익숙하지 않으시다면 전체적인 프로세스를 개괄적으로 봐주시거나 아래 링크를 통해 모르는 부분을 질문해 보시길 추천드립니다.&lt;/blockquote&gt;
&lt;p style=&quot;color: #555555; text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이번 포스트에선 &lt;b&gt;Spring Boot, React.js, Docker, AWS&lt;/b&gt;를 사용했던 기존 프로젝트에 github actions를 활용하여 CI/CD 파이프라인을 구축하는 것을 다루겠습니다. 사실 현재 취직 전 막바지로 자바와 스프링 부트에 대한 복습을 하고 있었어서 따로 토이 프로젝트를 또 하거나 블로그 포스팅을 하려는 생각은 딱히 없었습니다만...&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;최근 이력서를 다듬다가 배포된 프로젝트가 잘 작동하는지 살펴보는데 질문 과정에서 아래와 같이 에러 메시지만&amp;nbsp;계속&amp;nbsp;날리고 있었습니다.&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IHgEW/btsEhlxEvHy/PHXSQ5odc181AGsfmv04Q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IHgEW/btsEhlxEvHy/PHXSQ5odc181AGsfmv04Q0/img.png&quot; data-alt=&quot;...?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IHgEW/btsEhlxEvHy/PHXSQ5odc181AGsfmv04Q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIHgEW%2FbtsEhlxEvHy%2FPHXSQ5odc181AGsfmv04Q0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;294&quot; height=&quot;102&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;230&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;...?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애초에 클라이언트에서 api 통신 에러 시 발생하는 모든 오류 메시지는 위로 통일했었기 때문에 브라우저상으론 알기 어렵고, 그래서 직접 배포된 서버에 가서 확인해 봤습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;107&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3c4vl/btsEeMoRmL4/I69mQ4uauM69F5INSNrTgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3c4vl/btsEeMoRmL4/I69mQ4uauM69F5INSNrTgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3c4vl/btsEeMoRmL4/I69mQ4uauM69F5INSNrTgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3c4vl%2FbtsEeMoRmL4%2FI69mQ4uauM69F5INSNrTgk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;107&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;107&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한마디로 gpt api에게 요청할 때 기존에 사용했던 언어 모델인 text-davinci-003을 더 이상 사용할 수 없다는 거였죠. 애초에 현재 오픈된 gpt도 3에서 3.5로 업데이트되었기에 어쩌면 당연했었는데 좀 방치해 둔 감이 있었습니다. 그래도 공식 docs를 읽어보니 기존 엔진은 24년 1월 4일부로 더 이상 쓸 수 없다는 것 같았고 제가 며칠에 한 번은 체크하고 있었어서 바로 다음날 발견했기에 다행이긴 하네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여하튼 &lt;u&gt;이 엔진만 바꿔주도록 서버에 코드 몇 줄만 수정해 주면 간단히 해결될 문제&lt;/u&gt;... 였겠지만 현재 제&lt;b&gt; 배포 방식으론 그렇게 간단하게 수정할 수 있지 않더라고요.&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;204&quot; data-origin-height=&quot;204&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EiM7u/btsEiiG4WjS/LzcwkKhQ5i8GQHUaqjxd90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EiM7u/btsEiiG4WjS/LzcwkKhQ5i8GQHUaqjxd90/img.png&quot; data-alt=&quot;흠...&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EiM7u/btsEiiG4WjS/LzcwkKhQ5i8GQHUaqjxd90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEiM7u%2FbtsEiiG4WjS%2FLzcwkKhQ5i8GQHUaqjxd90%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;137&quot; height=&quot;137&quot; data-origin-width=&quot;204&quot; data-origin-height=&quot;204&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;흠...&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'아니 이렇게 간단한 수정 사항도 서버에 적용하고 &lt;b&gt;도커로 다시 빌드하고 서버 파일 교체하고 설정해 주고 도커 다시 켜주고....&lt;/b&gt; 를 해야 한다고?'란 생각에 귀찮음이 몰려오던 그때, 더 귀찮아질 미래를 모르고 전 생각했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;'아 그냥 자동 배포를 배워서 적용해 두면 저 귀찮은 짓을 할 필요 없겠지?'&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;CI/CD?&lt;/blockquote&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;왜 CI/CD를 학습하려고 했는지 빌드업은 충분히 길게 쓴 것 같으니 제가 적용한 방식을 간단히 말하자면 &lt;b&gt;github에 commit만 push시 EC2의 라이브 서버에 자동 배포되도록 한 게 전부&lt;/b&gt;입니다. 간단하죠? 그런데 사실 이 과정은 실무에서 적용된 CI/CD 파이프라인의 프로세스를 엄청 압축한 것입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이 글을 보신다면 CI/CD가 대충 무엇인지 아시겠지만 조금 설명해 보면 &lt;span style=&quot;text-align: start; color: #000000;&quot;&gt;CI/CD는 지속적 통합(Continuous Integration)과 지속적 배포(Continuous Deployment)의 약자*입니다. 한마디로 CI/CD 는 소프트웨어 개발 및 배포 프로세스를 자동화하고 효율적으로 관리하기 위한 방법론과 도구들을 포함합니다. 더 간단히 서버 개발자용으로 요약하자면 &lt;b&gt;'개발자가 코드만 수정하면 자동으로 테스트, 빌드, 배포, 환경 설정은 알아서 해주도록 구성해 놓는&lt;/b&gt; 것'을 뜻하죠.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;i&gt;&lt;span style=&quot;text-align: start; color: #000000;&quot;&gt;* 바로 다음에서 추가 내용 서술&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;text-align: start; color: #000000;&quot;&gt;CD는 사실 지속적 배포뿐만 아니라 지속적 전달(&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;Continuous&lt;/span&gt; Delivery)의 약자기도 합니다. 그래서 CD를 말하면 엄밀히 두 단어를 구분해야 맞겠지만 일반적으론 두 단어를 혼용하거나 두 단어가 가진 뜻을 합친 내용이 CD로 간주되기도 합니다. 그렇기에 보통 CI/CD를 구축한다고 하면 간단하게 다음과 같은 프로세스를 따라갑니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1258&quot; data-origin-height=&quot;550&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pePRc/btsEb9rMasK/6kkAVpcCKkIXMkNWblXM6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pePRc/btsEb9rMasK/6kkAVpcCKkIXMkNWblXM6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pePRc/btsEb9rMasK/6kkAVpcCKkIXMkNWblXM6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpePRc%2FbtsEb9rMasK%2F6kkAVpcCKkIXMkNWblXM6K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;497&quot; height=&quot;217&quot; data-origin-width=&quot;1258&quot; data-origin-height=&quot;550&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;CI/CD 방법론을 더 풀어서 보자면 이거보다 훨씬 더 길지만 서버 개발자가 숙지할 사항으론 이 정도면 충분합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;개발에 입문하시고 작은 프로젝트만 하셨다면 &lt;b&gt;굳이 복잡한 파이프라인을 타고 CI/CD를 왜 도입해야 하나?라고&lt;/b&gt; 생각하실 수도 있습니다. 하지만 프로젝트 규모가 커지고 투입되는 개발자가 많아진다면 이는 필수로 도입해야 합니다. CI 도입 필요성의 단적인 예로 과거 회사들에서 배포 전에는 모여서 코드를 통합하는 날을 따로 가졌었다고 합니다. 그 정도로 코드 통합과 테스트는 매우 중요한 일인데 이걸 자동화하면 아낄 수 있는 비용이 엄청나겠죠, 또 한 번이라도 내 프로젝트를 웹으로 배포해 본 경험이 있으시다면 CD의 중요성을 설명할 필요가 없을 정도로 체감하시리라 생각합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;추가 : CI/CD에 대해서 찾아보실때, 클라우드 지식 뿐만 아니라 무중단 배포나 IaC, DevOps에 대해 찾아보시면 좋을 것 같습니다.&lt;/blockquote&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;프로젝트에 적용&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 기존에 알고 있었고 보통 입문자라면 이렇게 알법한, 제가 이전 프로젝트에 사용했었던 CI/CD 파이프라인은 다음과 같습니다,&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blwWPz/btsEdGbHpeV/ykrRajIp0U3iu38aJwx5T1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blwWPz/btsEdGbHpeV/ykrRajIp0U3iu38aJwx5T1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blwWPz/btsEdGbHpeV/ykrRajIp0U3iu38aJwx5T1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblwWPz%2FbtsEdGbHpeV%2FykrRajIp0U3iu38aJwx5T1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;535&quot; height=&quot;301&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;900&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;이 프로세스의 가장 큰 장점은 빌드와 배포가 분리&lt;/b&gt;&lt;/u&gt;된 점입니다. 원래라면 AWS CodeDeploy의 경우 git의 코드를 직접 받아서 빌드와 배포를 한 번에 진행할 수도 있습니다. 한마디로 위 과정에서 Travis CI와 S3를 사용하지 않을 수 있죠. 하지만 실무에서 CI/CD를 도입할 때 그렇게 빌드와 배포를 묶어버리면 확장성이 많이 떨어집니다. 단적인 예로 빌드를 하지 않고 배포를 해야 하는 경우에도 쓸데없이 빌드를 해야만 하므로 보통 실무에선 위처럼 둘을 분리해서 프로세스를 짜는 걸 추천합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만&lt;u&gt;&lt;b&gt; 이 프로세스의 가장 큰 단점도 빌드와 배포가 분리됐다는 것&lt;/b&gt;&lt;/u&gt;입니다. 실무에선 여러 커스텀 설정에 용이하도록 프로세스를 세밀하게 분리하는 것이 당연합니다. 하지만 개인이 프로젝트에 CI/CD 구축을 경험하기엔 위의 프로세스는 대단히 번거롭습니다. AWS안에서 S3, CodeDeploy, EC2, RDS가 통합되어 있으니 조금 접근성은 있을지 몰라도 일단 하나하나 공부해야 하는 것은 달라지지 않습니다. 그런데 여기에 Travis CI, jupyter notebook까지 알아야 하죠. 뭐 사실 다른 프로세스도 각 툴들을 공부해야 하니 사실 학습할 게 많다는 것은 크게 와닿지 않을 수 있습니다. 하지만 &lt;u&gt;&lt;b&gt;제일 중요한 것은 너무 도구들을 많이 사용하다 보니 도구들 간의 설정 또한 그만큼 일일이 해줘야 한다는&lt;/b&gt;&lt;/u&gt; 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 스프링 부트로 코드를 짤 땐 build.gradle에 사용할 라이브러리명만 추가해 줘도 자동으로 버전을 설정해 주니 참 편합니다만 CI/CD에선 다릅니다. EC2에 관련 툴들을 깔 때도 모두 버전을 체크해줘야 하는 것부터 Travis CI와 AWS 간 IAM 등의 설정까지... 말하기도 너무 긴 과정을 직접 해줘야 합니다. 이렇게 설정을 많이 건드리고 리눅스에서 개발자가 해야 할 일이 많기에 접근성이 좋을래야 좋을 수가 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 앞서 얘기한 것처럼 S3와 Travis CI를 쓰지 않고 CodeDeploy로 빌드와 배포를 한 곳에 묶어 버릴 수도 있습니다만 이 역시 git과 CodeDeploy를 연동해야 하기에 설정할 게 좀 많습니다.(실제로 설정하다가 며칠 날려봤기도 하고...)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 제가 처음 새로운 토이 프로젝트를 시작했을 때 너무 많은 시간이 뺏길 거 같아서 간단하게 스크립트 배포로 끝냈던 것 같네요. 그런데 이번에 새로 학습한 프로세스는 보다 간단했고 시간도 그렇게 크게 뺏기지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w3Zup/btsEkSVUNfi/eHUXHbSlBzZWVaDNfGp0A0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w3Zup/btsEkSVUNfi/eHUXHbSlBzZWVaDNfGp0A0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w3Zup/btsEkSVUNfi/eHUXHbSlBzZWVaDNfGp0A0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw3Zup%2FbtsEkSVUNfi%2FeHUXHbSlBzZWVaDNfGp0A0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;569&quot; height=&quot;320&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;900&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 수정된 프로세스의 가장 큰 장점은 &lt;b&gt;CI/CD에 사용되는 플랫폼이 Git과 AWS으로 단 둘만 존재&lt;/b&gt;한다는 것입니다.&lt;b&gt; 아무리 서비스 간 통합이 잘 되어 있어도 사용하는 플랫폼이 다르다면 무조건 설정에 학습 시간을 써야만 합니다. 또한 사용해야 하는 툴을 처음 접한다면 더더욱이요.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;141&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PpTnG/btsEiyC3RUR/UhiAvMOFvNISj60eTcSxi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PpTnG/btsEiyC3RUR/UhiAvMOFvNISj60eTcSxi0/img.png&quot; data-alt=&quot;github 레포 메뉴에 바로 보이는 Actions&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PpTnG/btsEiyC3RUR/UhiAvMOFvNISj60eTcSxi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPpTnG%2FbtsEiyC3RUR%2FUhiAvMOFvNISj60eTcSxi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;674&quot; height=&quot;141&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;141&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;github 레포 메뉴에 바로 보이는 Actions&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 우리가 개발할 때 VCS로 git을 안 써본 사람이 있을까요? 게다가 이 프로세스는 빌드와 배포를 github actions에서 워크플로우 파일 하나만 작성한다면 ok므로 정말 간단합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 질문이 있을 수도 있습니다. &lt;b&gt;'actions를 사용해도 aws와 통합해야 하니 설정이 필요한데 기존처럼 CodeDeploy를 사용해도 어차피 git과 설정하는 거나 다른 게 없지 않냐?'라고요.&lt;/b&gt; 맞습니다. 그래서 &lt;u&gt;우리는 이 프로세스에서 Docker를 추가로 사용&lt;/u&gt;하는 겁니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 프로젝트에선 CodeDeploy를 통해 스크립트로 배포했었습니다. 하지만 그 과정에선 EC2에 직접 java와 node.js를 설치해야 하고 버전을 충돌하지 않게 맞춰줘야 하고 VPC와 서브넷도 직접 관리해줘야 하는 등 배포 과정 중 직접 해야 할 설정이 너무 많았습니다. 하지만 도커를 사용하면 이런 쓸데없는 설정들 필요 없이 EC2에 도커만 설치해 주면 간단히 끝납니다. 게다가 위 그림을 보시면 포워드 프록시로 nginX가 추가된 것을 보실 수 있는데 도커를 사용한다면 EC2에 특별히 다른 작업을 해줄 필요가 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;혹시 도커를 모르는 분들이 있을 수 있는데 간단히 말하면 &lt;b&gt;개발 환경에 구애받지 않고 서비스할 수 있는 가상화된 컨테이너 기술&lt;/b&gt;입니다. 우리가 개발해서 로컬로 테스트하려면 프로젝트에 맞는 언어도 설치해야 하고, 라이브러리도 받아와야 하고, 버전도 서로 맞춰줘야 합니다. 그런데 도커를 사용한다면 그냥 도커만 깔면 컨테이너 안에서 테스트를 진행할 수 있는 거죠. 쉽게 맥을 사용하는데 윈도우를 켜기 위해 사용하는 VM머신과 비슷하다고 생각하면 됩니다. 자바를 사용하신다면 JVM을 떠올리시면 되겠죠?&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 기존에 배포된 EC2 서버를 관리하기 위해 jupyter notebook을 사용했었습니다. 제가 사용하는 노트북의 OS가 윈도우기 때문에 EC2를 관리하려고 SSH연결을 하려면 Putty가 필수적이고 pem키를 등록해 뒀다고 하더라도 &lt;b&gt;매번 putty를 통해 EC2를 관리하고 모니터링하는 건 매우 매우 귀찮은 일&lt;/b&gt;이었습니다. 그래서 &lt;b&gt;웹으로 EC2에 접근하기 위해 &lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;jupyter notebook을 설치하긴 했지만 이것도 초기 설정이 매우 매우 많습니다.&lt;/b&gt; 또한 이후 연결도 인증서 갱신이나 이런 게 필요해서 번거로운 점이 많았죠. 이것을 대체하기 위해 AWS에서 제공하는 SSM을 사용해 애초에 세션에 접근할 때 SSH연결 자체를 아예 할 필요 없게&lt;/span&gt;되어서 매우 편해졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;추가 : 이 포스트에는 EC2를 활용한 정말 기초적인 파이프라인에 대해서 다룬만큼 클라우드에 입문을 위한 팁 정도로 봐주시면 감사하겠습니다. 실제로 실무에선 IaaS뿐만 아닌 ECS+Fagate나 EKS나 AKS(벤더사별 k8s 구현) 등등 이것 말고도 정말 다양한 클라우드 활용 방식이 존재하며 온프레미스+클라우드 하이브리드 방식 또한 많이 사용되고 무엇이 낫다가 절대 아닌 비용과 규모, 환경을 모두 고려하여 결정된다는 점을 반드시 알아주세요.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스트에선 일단 CI/CD를 프로젝트에 적용한 개괄적인 프로세스에 대해 간단히 적어봤습니다. 물론 CI/CD를 사용할 때 GitLab, Jenkins, CircleCI, AWS CodePipeline 등 본인에게 더 적합한 툴들이 많고 당연히 익숙하다면 그것들을 사용하면 됩니다. 하지만 기본적으로 github를 다들 사용하는 현재 github actions를 사용하는 건 매우 접근성도 좋고 합리적이라고 생각하기에 프로젝트에 적용해 봤고 이렇게 포스팅합니다. 다음 포스트에선 어떻게 제 프로젝트에 이 프로세스를 적용했는지 다루도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;refer&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.hanl.tech/blog/ci-cd-%EA%B8%B0%EB%B3%B8%EA%B0%9C%EB%85%90%EA%B3%BC-%EA%B0%80%EC%9E%A5-%EB%A7%8E%EC%9D%B4-%EC%93%B0%EC%9D%B4%EB%8A%94-%EB%8F%84%EA%B5%AC-5%EA%B0%80%EC%A7%80/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.hanl.tech/blog/ci-cd-%EA%B8%B0%EB%B3%B8%EA%B0%9C%EB%85%90%EA%B3%BC-%EA%B0%80%EC%9E%A5-%EB%A7%8E%EC%9D%B4-%EC%93%B0%EC%9D%B4%EB%8A%94-%EB%8F%84%EA%B5%AC-5%EA%B0%80%EC%A7%80/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1706714737347&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;CI/CD 기본개념과 가장 많이 쓰이는 도구 5가지 | 하늘네트&quot; data-og-description=&quot;CI/CD란? CI = 지속적인 통합(Continuous Integration); 한마디로 &amp;ldquo;빌드와 테스트 자동화&amp;rdquo;&amp;nbsp; CD = 지속적인 전달(Continuous Delivery) 또는 지속적인 배포(Continuous Deployment); 한마디로 &amp;ldquo;배포 자동화&amp;rdquo;&amp;nbsp; 덧붙이&quot; data-og-host=&quot;www.hanl.tech&quot; data-og-source-url=&quot;https://www.hanl.tech/blog/ci-cd-%EA%B8%B0%EB%B3%B8%EA%B0%9C%EB%85%90%EA%B3%BC-%EA%B0%80%EC%9E%A5-%EB%A7%8E%EC%9D%B4-%EC%93%B0%EC%9D%B4%EB%8A%94-%EB%8F%84%EA%B5%AC-5%EA%B0%80%EC%A7%80/&quot; data-og-url=&quot;https://www.hanl.tech/blog/ci-cd-기본개념과-가장-많이-쓰이는-도구-5가지/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bT8Pih/hyVf8f7699/oAk1lCdIi0r8sggdjcQdE1/img.jpg?width=1024&amp;amp;height=640&amp;amp;face=0_0_1024_640,https://scrap.kakaocdn.net/dn/cQCe4Y/hyVf0WH0FY/q4b9F74N3qpNtNzsSYtjX0/img.jpg?width=1366&amp;amp;height=768&amp;amp;face=0_0_1366_768,https://scrap.kakaocdn.net/dn/bMVon9/hyVb7b7KLr/81Hfd2VMHxHf31VZmR0xZ0/img.jpg?width=1020&amp;amp;height=600&amp;amp;face=0_0_1020_600&quot;&gt;&lt;a href=&quot;https://www.hanl.tech/blog/ci-cd-%EA%B8%B0%EB%B3%B8%EA%B0%9C%EB%85%90%EA%B3%BC-%EA%B0%80%EC%9E%A5-%EB%A7%8E%EC%9D%B4-%EC%93%B0%EC%9D%B4%EB%8A%94-%EB%8F%84%EA%B5%AC-5%EA%B0%80%EC%A7%80/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.hanl.tech/blog/ci-cd-%EA%B8%B0%EB%B3%B8%EA%B0%9C%EB%85%90%EA%B3%BC-%EA%B0%80%EC%9E%A5-%EB%A7%8E%EC%9D%B4-%EC%93%B0%EC%9D%B4%EB%8A%94-%EB%8F%84%EA%B5%AC-5%EA%B0%80%EC%A7%80/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bT8Pih/hyVf8f7699/oAk1lCdIi0r8sggdjcQdE1/img.jpg?width=1024&amp;amp;height=640&amp;amp;face=0_0_1024_640,https://scrap.kakaocdn.net/dn/cQCe4Y/hyVf0WH0FY/q4b9F74N3qpNtNzsSYtjX0/img.jpg?width=1366&amp;amp;height=768&amp;amp;face=0_0_1366_768,https://scrap.kakaocdn.net/dn/bMVon9/hyVb7b7KLr/81Hfd2VMHxHf31VZmR0xZ0/img.jpg?width=1020&amp;amp;height=600&amp;amp;face=0_0_1020_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;CI/CD 기본개념과 가장 많이 쓰이는 도구 5가지 | 하늘네트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;CI/CD란? CI = 지속적인 통합(Continuous Integration); 한마디로 &amp;ldquo;빌드와 테스트 자동화&amp;rdquo;&amp;nbsp; CD = 지속적인 전달(Continuous Delivery) 또는 지속적인 배포(Continuous Deployment); 한마디로 &amp;ldquo;배포 자동화&amp;rdquo;&amp;nbsp; 덧붙이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.hanl.tech&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Project</category>
      <category>AWS</category>
      <category>cd</category>
      <category>ci/cd</category>
      <category>docker</category>
      <category>github actions</category>
      <category>배포 자동화</category>
      <author>fadet</author>
      <guid isPermaLink="true">https://fadet-coding.tistory.com/92</guid>
      <comments>https://fadet-coding.tistory.com/92#entry92comment</comments>
      <pubDate>Thu, 1 Feb 2024 00:28:07 +0900</pubDate>
    </item>
    <item>
      <title>JAVA_4_중첩클래스(Nested)와 Static(+jvm, 스프링 부트)</title>
      <link>https://fadet-coding.tistory.com/90</link>
      <description>&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;*&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;이 포스트는 학습 과정에서 그 내용을 기록한 글이기에 부정확한 정보가 포함될 수 있습니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;따라서 해당 글은 참고용으로만 봐주시고 틀린 부분이 있다면 알려주시면 감사하겠습니다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;❗&amp;nbsp;이번 포스트는 인프런 강의 중 토비 님의 '토비의 스프링 부트 - 이해와 원리'를 수강하고 배운 내용을 정리하여 작성하였습니다. 그렇기에 조금 더 내용을 깊게 알기 원하시면 직접 강의를 수강하시길 추천합니다. 또한 해당 내용은 토비 님의 유튜브 채널 링크&amp;nbsp;&lt;a href=&quot;https://www.youtube.com/watch?v=2G41JMLh05U&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.youtube.com/watch?v=2G41JMLh05U&lt;/a&gt;를 같이 보시면 좋습니다.&lt;br /&gt;&lt;br /&gt;❗ 이번 포스팅은 지난 글인&amp;nbsp;&lt;a href=&quot;https://fadet-coding.tistory.com/26&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://fadet-coding.tistory.com/26&lt;/a&gt;&amp;nbsp;에서 이어집니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;❗ 포스트를 보실때 미리 알면 도움이 될 지식 : 자바(JVM 메모리 파트), 스프링부트(스프링빈과 어노테이션)&lt;i&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/i&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스트는 사실 스프링 부트를 학습하면서 공부한 내용이지만 내용상 저번에 작성했던 JAVA 관련 포스팅과 긴밀하게 이어져서 JAVA 카테고리로 정했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 포스트에서 static class에 대해서 짧게 언급을 했었는데, 자바를 처음 공부할 때의 글이기도 하고 복습할 겸 다시 읽어보니 좀 부정확한 표현도 있더라고요. 그래서 개념도 다시 정리하고 강의 내용도 복습할 겸 그리고 이전 포스트에서 간단히 설명하고 넘어간 내용에 대해 추가 포스팅하려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저번에 Nested Class(이후로 중첩 클래스라고 표기)를 얘기하면서 중첩 클래스는 되도록 static class로 만드는 것을 권장한다고 넘어갔었는데, 이 말은 따지고 보면 정확하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 자바를 배우신분들은 중첩 클래스가 일반 중첩클래스(inner nested class)와 스태틱 중첩클래스(static nested class)로 나뉜다고 알고 계실 것이고 저도 그렇게 알고 있습니다. 하지만 단순히 이렇게 이분법적으로 개념에 접근하면 다소 부정확하게 알고 넘어가실 것이라고 생각합니다. 이에 대해서는 지금 결론짓지 않고 쭉 내용을 정리한 다음 포스트 후반부에 결론을 짓겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 포스트에서 &lt;u&gt;&lt;b&gt;제가 모든 Outer Class(.java파일을 구성하는)를 사실상 (static) Class로 이해하는게 낫다&lt;/b&gt;&lt;/u&gt;는 언급을 했었습니다. 사실 &lt;b&gt;입문서 어느걸봐도 (static) Class에 대한 내용은 없습니다. 또 제가 말한 것처럼 논리적으로 이해할때 편하다 뿐이지 실제로는 Outer class 앞에 static이 붙을 수 없습니다.&lt;/b&gt; 그런데 왜 제가 이런 얘기를 꺼냈을까요? 다음 문단부터는 그에 대한 자세한 얘기를 해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nested Class(중첩 클래스)를 포함하는 가장 상위 클래스를 보통 Outer Class, Top-level Class로 표현하는데 여기선 그냥 짧으니 Outer Class로 칭하겠습니다. 여기서 지난번 포스트에 작성했던 얘기를 꺼내보자면 우리는 static &lt;u&gt;nested&lt;/u&gt; class에 대해선 배운 적이 있습니다만 static &lt;u&gt;outer&lt;/u&gt; class에 대해선 들어본 적도 배운 적도 없습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1698662944664&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Outer { // static class Outer X 
	static class Inner // static class Inner O
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 왜 outer class엔 static이 붙을 수 없는가에 대해 찾아보았고 이에 대해 가장 많은 공감을 얻은 답변을 stackoverflow에서 찾아보았더니 아래와 같았습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;All top-level classes are, by definition, static.(모든 상위 클래스들은 정의상으론 정적입니다.)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한마디로 모든 상위 클래스 앞에는 (static)이 붙어 있단 소립니다. 하지만 찾아보다 보니 공식적으론 정확하게 사실과 일치하지는 않습니다. 위의 문장이 stackoverflow에서 가장 많은 투표를 받은 답변이고 아래는 그다음 투표수를 받은 답변입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Simply put, a top-level type declaration cannot be static, because the Java Language Specification(JLS) doesn'tsay that it can be. The JLS says this explicitly about the&amp;nbsp;static&amp;nbsp;keyword as a modifier of top-level classes:&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;답변 내용은 자바 공식 문서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;top level(outer) 클래스, 지역 클래스, 익명 클래스는 static 키워드를 붙일 수 없도록&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;제한할 뿐이라고 되어있습니다. 해당 답변을 더 찾아 읽어보시면 JAVA에서 규정된 static이 붙을 수 있는 요소들을 나열하고 끝에 정의상으로 정적이라는 이전 답변은 사실이 아님을 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stackoverflow를 더 살펴보고 다른 글들도 찾아보며 내린 결론은 후자의 답변인 공식 문서가 더 맞지 않을까였습니다. 아니 공식 문서가 그렇게 하라는데 이게 맞겠죠? 그런데 좀 찝찝합니다. 그리고 또 왜 제가 맞다고 생각하지도 않는 답변을 먼저 소개해드렸을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국엔 저도 궁금했던 거예요. &lt;b&gt;'아니 도대체 왜 공식 문서에서 그렇게 소개하지도 않은 내용을 그렇게 많은 개발자들이 공감할까?'&lt;/b&gt;.&amp;nbsp;실제로 저 답변 말고도 많은 답변들이 저것과 거의 같은 뉘앙스였습니다. 또 제가 처음 배울 때도 그렇게 알고 넘어갔었거든요. 그래서 궁금해졌습니다. 공식 문서상에는 기술되어있지 않지만 많은 개발자들이 말하는 대로 outer class가 정말 암시적으로 static과 같이 작동하는지 말이죠. 이것을 이해하기 위해선 JVM의 작동 방식에 대해서 좀 알아야 할 필요가 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;i&gt;* 이 글을 작성하며 더&amp;nbsp; 찾아봤는데&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0c0d0e; text-align: left;&quot;&gt;Java SE 19 Specification에&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;outer class도 암시적으로 static이라는 문구가 있다고 합니다만 사실 두 답변이 서로 배치되는 말을 하는 건 아니었기도 하고 제 글의 결론 자체도 두 답변 모두 인정하기 때문에 더 언급하지 않고 여기서 넘어가겠습니다. 제가 참고한 질문은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://stackoverflow.com/questions/7370808/why-cant-a-top-level-class-be-static-in-java&quot;&gt;https://stackoverflow.com/questions/7370808/why-cant-a-top-level-class-be-static-in-java&lt;/a&gt;입니다.&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;실제로 intelliJ같은 IDE상에서 class 앞에 static을 붙여보면 'Modifier 'static' not allowed here'라며 컴파일이 불가능합니다. 만약 논리적인 개념이 아닌 실제 문법상으로도 (static) class가 맞다면 컴파일이 가능하거나 static이 비활성화되어야 할겁니다.(인터페이스의 경우 멤버 메서드에 생략이 가능한 public abstract를 붙이면 자동 비활성화됩니다.)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;JVM의 메모리 관리&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMsd5D/btszwhMLkmg/vyz8jOM7IOIHgqB9C3iqDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMsd5D/btszwhMLkmg/vyz8jOM7IOIHgqB9C3iqDK/img.png&quot; data-alt=&quot;간단한 JVM 구성 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMsd5D/btszwhMLkmg/vyz8jOM7IOIHgqB9C3iqDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMsd5D%2FbtszwhMLkmg%2Fvyz8jOM7IOIHgqB9C3iqDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;589&quot; height=&quot;441&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;간단한 JVM 구성 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스트에선 JVM이 어떻게 동작하는지 상세하게 설명하지는 않겠습니다. 따라서 더 자세히 알고 싶으시다거나 아예 모르신다면 참조 링크를 이용해 주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;# Class Loader&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 이 글을 보신다면 우리가 &lt;b&gt;*. java&lt;/b&gt; 파일에 JAVA 언어로 코드를 짜면 컴파일러는 이를 &lt;b&gt;*. class로&lt;/b&gt; 된 바이트코드 파일을 생성한다는 것 정도는 아실 겁니다. 여기서 &lt;b&gt;우리가 알아야 할 첫 단계&lt;/b&gt;는&lt;b&gt; Class Loader&lt;/b&gt;입니다. 클래스 로더는 .class로 된 바이트코드를 엮어서 Runtime Data Area로 load 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 이후에 적재된 바이트코드를 engine이 실행하는데 이 과정에서 인터프리터와 JIT 컴파일러가 혼합되어 쓰이고 이 이후 주로 Runtime Data Area의 Heap 메모리 영역을 청소하는 Garbage Collector가 관여합니다. 간단하게 한 줄로 넘어갔지만 이 부분도 잘 모르신다면 링크를 통해 더 자세히 공부하시길 추천합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;# Runtime Data Area - Method Area&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다음 &lt;b&gt;우리가 알아야 할 두 번째는&lt;/b&gt; Method Area입니다. 이전 글을 보셨거나 메모리 관리에 대해 공부해 보셨다면 Heap이나 Stack 정도는 아실 것이라 생각합니다만 의외로 Method Area에 대해 잘 알고 계신 분들은 많지 않은 것 같더군요,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 그게 어쩌면 당연하긴 합니다. 사실 Method Area는 Java에서 개발자가 대부분 코드로 성능을 개선하고 주로 살펴보는 부분은 아니거든요. 그래서 짧게 언급하고 넘어가겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Method Area는 MetaSpace라고도 불리지만 일부에선 Class Area, Static Area로도 불립니다. 이름처럼 이곳엔 클래스와 인터페이스의 타입 정보, 그 메서드, 필드의 정보와 런타임 상수 풀 등을 보관합니다. 한마디로 static 필드는 다 이곳에 보관되는 거죠. 우리가 이전 포스트에서 메모리가 사용될 때 DATA 영역에 static이 저장된다고 들었을텐데 JVM에서 쓰는 명칭은 살짝 다른거죠. 한마디로 우리가 학습할 때 &lt;u&gt;&lt;b&gt;Method Area, DATA Area, Class Area, Static Area는 모두 같은 개념&lt;/b&gt;&lt;/u&gt;이라고 생각하시면 편합니다. 인스턴스와 객체는 분명 다른 개념이지만 자바를 배울땐 혼용해서 칭하는 것과 비슷하겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bn8Amv/btszqce1evv/aQyeBwsUAEbfEW1ut5v3BK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bn8Amv/btszqce1evv/aQyeBwsUAEbfEW1ut5v3BK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bn8Amv/btszqce1evv/aQyeBwsUAEbfEW1ut5v3BK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbn8Amv%2Fbtszqce1evv%2FaQyeBwsUAEbfEW1ut5v3BK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;416&quot; height=&quot;297&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;526&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Static&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;우선 자바를 입문하면 Static은 변수나 메서드 같은 필드 앞에 붙여서 객체를 매번 생성할 필요 없이 하나의 멤버를 어디서나 참조할 수 있도록 하는 접두 키워드고, 이를 잘 이용하면 메모리 관리에도 이점이 있다고들 배웁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;그래서 처음 배울 때 책으론 클래스 멤버는 뭘 참조할 수 없고, 인스턴스 멤버는 어쩌고...&amp;nbsp; 하면서 좀 복잡하게 배우기 때문에 이를 좀 간단히 이해해 보자 하고 쓴 게 이전 포스트였습니다. &lt;b&gt;static 멤버나 static 블록처럼 static 키워드가 들어가면 모두 static area에 저장돼서 heap에서 객체를 생성할 필요 없이 언제나 참조할 수 있다&lt;/b&gt;라고요. 그러면 우리가 뭐 클래스 멤버 인스턴스 멤버 이렇게 구분할 필요 없이 코드를 짜는데 도움이 될 것 같았거든요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;여기서 아까 얘기를 다시 해보자면 '&lt;b&gt;어차피 static 키워드가 붙은 요소들은 함께 static area에 저장되고 outer class도 사실상 (static)이 생략되어 있다고 생각하면 모두 한 곳에 저장되어 있다고 생각할 수 있어서 편하다.'&lt;/b&gt; 이렇게 얘기했었는데, 이 말을 들으니 뭔가 생각나는 게 있지 않으세요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;맞습니다. 많은 개발자들이 얘기하던 정의상으론 outer class는 이미 static이다라는 답변이 제가 말한 것과 정확히 일치합니다. 어쩌면 당연한 말이었을지도 모릅니다. 의미상 static이란건 dynamic의 반대말이고 동적으로 객체를 생성하며 할당하지 않고 클래스 로더 과정에서 참조할 수 있는 요소들을 만드는 과정은 전부 static으로 생각하면 되니까요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;이를 자바 공식 문서상에선 hierarchy를 명확히 해야 했거나 OOP 언어적 특성을 확실히 하기 위해서 outer class에 static을 붙이는 걸 제한했다고 생각하지만 이 규정만 위배되지 않는다면 논리적으로 이해하는데 문제 될 것이 없습니다. 그렇기에 많은 개발자들이 outer class는 이미 static이므로 또 static 키워드를 붙일 이유가 없다고 말한 겁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Outer Class와 Static Nested class&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왜&lt;/b&gt; &lt;b&gt;static outer class란 존재하지 않는가?&lt;/b&gt;에 대한 가장 간단한 답은 oracle이 말한 outer class에 static이 붙는 걸 제한한다라는 문법일겁니다. 하지만 실제 문법에 위배되지 않는다면 논리적인 구조도는 개념 이해에 큰 도움이됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 나아가 이렇게 이해한다면 처음 화두로 꺼낸 이야기에 대해서도 쉽게 이해가 되실 겁니다. &lt;b&gt;'nested class는 static으로 만들 것을 권장한다.'&lt;/b&gt; 이것은 IDE에서도 경고 메시지로 출력되는 내용입니다. 이 개념을 암기식으로&lt;i&gt; 'nested class의 종류가 static과 non-staic 두 가지로 구분되고 각각 용례는 이렇다. ~'&lt;/i&gt; 이렇게 외우시면 꽤나 헷갈리실 겁니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 static nested class를 중첩 클래스로 생각하지 않고 아예 같은 static이 붙은 (static) outer class와 큰 차이가 없다고 생각하면 정말 쉽게 넘어갈 수 있는 부분입니다. 단지 코드상 위치가 다른 것뿐이고 앞선 둘을 그냥 같은 class로 생각하여 실질적으로 nested class는 nested inner(non-static) class(이후 이너클래스) 하나만 있다고 생각하면 코드를 짤 때 전혀 헷갈리지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 단순히 말만 번지르르하게 맞춘 것이 아니라 메모리를 이용해 직접 코드상으로 실행해도 그렇습니다. 코드를 예시로 보여드리면 아래와 같이 non-static인 nested class인 Inner를 호출해 보면&lt;/p&gt;
&lt;pre id=&quot;code_1698671812895&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Outer {
    Outer() { System.out.println(&quot;&amp;gt; Outer 생성자 초기화&quot;); }

    // non-static nested class
    class Inner {
        Inner() { System.out.println(&quot;&amp;gt; Inner 생성자 초기화&quot;); }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1698671871213&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        new Outer().new Inner(); // 내부 클래스 인스턴스화
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZxTZ2/btszwb0dxBA/a0oLlGMvCrapDdK28DptAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZxTZ2/btszwb0dxBA/a0oLlGMvCrapDdK28DptAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZxTZ2/btszwb0dxBA/a0oLlGMvCrapDdK28DptAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZxTZ2%2Fbtszwb0dxBA%2Fa0oLlGMvCrapDdK28DptAK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;206&quot; height=&quot;194&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 상으로도 알 수 있지만 위와 같이 outer class를 먼저 로드하고 로드만 하는 게 아니라 인스턴스화시키기 때문에 우리가 흔히 아는 메모리 누수가 발생할 위험이 있습니다. 하지만 아래와 같이 static nested class인 Hoder를 호출해 보면&lt;/p&gt;
&lt;pre id=&quot;code_1698672084800&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Outer {  
    // static nested class
    static class Holder {
        static String value = &quot;&amp;gt; Holder 클래스의 static 필드 입니다.&quot;;
        static final String VALUE = &quot;&amp;gt; Holder 클래스의 static final 필드 입니다.&quot;;

        Holder() { System.out.println(&quot;&amp;gt; Holder 생성자 초기화&quot;); }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1698672128712&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        new Outer.Holder(); // static 내부 클래스 인스턴스화
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;261&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnJeiO/btszwf9kpPg/bPhWfOjsRuXffz064A2QK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnJeiO/btszwf9kpPg/bPhWfOjsRuXffz064A2QK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnJeiO/btszwf9kpPg/bPhWfOjsRuXffz064A2QK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnJeiO%2Fbtszwf9kpPg%2FbPhWfOjsRuXffz064A2QK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;222&quot; height=&quot;106&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;261&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;위와 같이 Outer는 인스턴스화되지 않고 오직 Holder만 인스턴스화되는 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 동적으로 클래스 정보를 담는 클래스로더 시점에서 static nested class가 있다면 Method area에 그게 포함된 class를 로드하긴 합니다만 실무에서 일하는 지인에게 물어본 바로는 그 정도는 Heap 관리를 못해서 GC 등으로 인해 생기는 메모리 누수에 비하면 미미한 정도라고 하기도 하고 제 생각에도 크게 영향을 끼칠 것 같진 않습니다. 이 부분에 대해서는 더 자세히 아시는 분 있으시다면 덧글 달아주시면 감사하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 Outer class와 static nested class는 사실상 동일시해도 큰 문제는 없습니다. 굳이 outer class로 작성하면 되지 왜 static nested class를 쓰냐라고 물어보신다면 우리가 패키지 같은 폴더를 사용하는 이유와 같다고 말씀드릴 것 같습니다. 또한 특정 outer class에서만 사용되는 static nested class가 있다면 코드 가독성 면에서도 좋고요. 그리고 간단히 코드를 짤 때 짧은 클래스를 매번 만들었다 지웠다 하기도 귀찮을 때 있잖아요? 그때 간단하게 사용할 수도 있고요.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;스프링 빈과 nested class&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;❗ 앞으로의 내용은 스프링 부트의 기본적인 내용을 숙지하신 분이 아니라면 이해하기 어려울 수 있습니다. 해당 부분을 보고 싶은데 스프링 부트를 잘 모르신다면 인프런에서 토비 님의 '토비의 스프링 부트 - 이해와 원리' 강의를 들어보시거나 스프링에 대한 기초를 학습하고 오시는 걸 추천드립니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스팅하려던 주 골자는 모두 얘기했고 지금부터는 순수 자바 환경이 아닌 스프링 환경에서의 nested class 얘기를 하려고 합니다. 이 부분은 사실 토비 님의 유튜브 영상으로 모두 설명이 되어 있어서 영상과 똑같은 얘기일 텐데 글로 짧게 풀어보겠습니다. 링크는 &lt;a href=&quot;https://www.youtube.com/watch?v=2G41JMLh05U&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=2G41JMLh05U&lt;/a&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 살펴본 바로 순수 자바 환경에서 static이 아닌 nested class, 즉 이너클래스는 &lt;b&gt;반드시 인스턴스화될 때&lt;/b&gt; &lt;u&gt;이너클래스가 포함된 outer class가 먼저 인스턴스화&lt;/u&gt;되고 이루어졌습니다. 이 점을 알고 스프링을 학습하다 보면 다음과 같은 문제를 만나게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 부트에서 자바 클래스를 스프링 빈으로 등록하는 방법엔 @Component 어노테이션을 클래스 상단에 붙여준다는 것은 아실 겁니다. 만약 그렇다면 &lt;b&gt;아래와 같은 코드에선 Inner class가 스프링 빈으로 등록돼서 콘솔창에 println메서드가 실행될까요?&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1698674131438&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@SpringBootApplication
public class OuterClass() {
	// non static nested class
    @Component
    class InnerClass {
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1698674394424&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
	ConfigurableApplicationContext ac = SpringApplication.run(SpringBeanTest.class, args);
    System.out.println(ac.getBean(OuterClass.class));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 글을 읽어오셨다면 이 코드는 실행 후 예외를 던져야 맞습니다. 왜냐하면 우리는 InnerClass를 인스턴스화하기 전에 먼저 OuterClass를 인스턴스화하는 과정을 빠트렸으니까요. 하지만 &lt;b&gt;유감스럽게도 위의 코드는 잘만 실행&lt;/b&gt;됩니다. 그렇다면 그 이유를 아시겠나요? 스프링 부트가 마법사라서?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 자세히 이 과정을 자세히 설명하고 싶지만 이 부분은 오늘 포스트의 주 이야깃거리가 아니기도 하고 소개드린 강의와 유튜브 영상으로 자세히 나와있기도 하니 간단히 설명하고 넘어가겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 저 코드에서 &lt;b&gt;OuterClass는 이미 인스턴스화되었기&lt;/b&gt; 때문입니다. 그런 코드가 안 보이신다고요? 잘 안 보이실 겁니다. 바로 OuterClass위에 붙은 @SpringBootApplication 때문이니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@SpringBootApplication에 대해 찾아보면 아래와 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;361&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dlwr3p/btszvIcRvMg/ISXpIDlZkRehuVTkizO3E1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dlwr3p/btszvIcRvMg/ISXpIDlZkRehuVTkizO3E1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dlwr3p/btszvIcRvMg/ISXpIDlZkRehuVTkizO3E1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdlwr3p%2FbtszvIcRvMg%2FISXpIDlZkRehuVTkizO3E1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;321&quot; height=&quot;162&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;361&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링을 학습하시다 보면 메타 애노테이션에 대해서 배우실 텐데요. 쉽게 말해서 애노테이션위에 붙는 애노테이션을 말하는 건데 그게 붙으면 동일한 효과를 얻는다고 보시면 편합니다. &lt;b&gt;@SpringBootApplication에 붙은 @SpringBootConfiguration&lt;/b&gt;이라는 메타 애노테이션이 보이시나요? 이 애노테이션을 따라가다 보면 @Component 애노테이션이 붙어 있습니다. 따라서 &lt;b&gt;OuterClass도 사실상 @Component&lt;/b&gt;가 붙어 스프링빈으로 이미 등록이 된 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 &lt;u&gt;InnerClass를 스프링빈으로 등록하기 전&lt;/u&gt;에 &lt;u&gt;컨테이너는 앞서 스프링빈으로 등록된 오브젝트를 뒤져&lt;/u&gt; &lt;u&gt;Outer클래스가 있는지 확인&lt;/u&gt;하고 &lt;u&gt;이게 이미 인스턴스화되었기 때문에 InnerClass도 문제없이 스프링빈으로 등록&lt;/u&gt;된 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글은 서두에서 얘기한 것처럼 스프링 부트 강의를 듣던 중 개념을 복습하기 위해서 작성했습니다. 글을 작성하다 보니 GC 등 Execution처럼 JVM의 세부 작동 원리와 그 과정에서 메모리 성능 개선 등에 대한 글도 찾아봤는데 나중에 기회가 되면 관련 부분도 포스팅해 보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;refer&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://www.inflearn.com/course/%ED%86%A0%EB%B9%84-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EC%9D%B4%ED%95%B4%EC%99%80%EC%9B%90%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.inflearn.com/course/%ED%86%A0%EB%B9%84-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EC%9D%B4%ED%95%B4%EC%99%80%EC%9B%90%EB%A6%AC&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1698680080350&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;토비의 스프링 부트 - 이해와 원리 - 인프런 | 강의&quot; data-og-description=&quot;스프링 부트의 핵심 기능을 직접 만들어보면서 스프링 부트의 동작 원리를 이해하고, 이를 통해 스프링 부트를 잘 학습하고 사용하는 방법을 배우는 강의입니다. 스프링 부트가 사용하는 스프&quot; data-og-host=&quot;www.inflearn.com&quot; data-og-source-url=&quot;https://www.inflearn.com/course/%ED%86%A0%EB%B9%84-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EC%9D%B4%ED%95%B4%EC%99%80%EC%9B%90%EB%A6%AC&quot; data-og-url=&quot;https://www.inflearn.com/course/%ED%86%A0%EB%B9%84-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EC%9D%B4%ED%95%B4%EC%99%80%EC%9B%90%EB%A6%AC&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/d0csZo/hyUkk4Rigg/8i5O5O5qs6uUZkq68Weio1/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/cNMQi3/hyUnNxu2DR/QCbB7x6FEiK91ZB50GN5t1/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/ydccr/hyUnQA0C7n/3TpU7z6qwu9sKQIkkbGGTK/img.png?width=1200&amp;amp;height=770&amp;amp;face=489_594_556_667&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/course/%ED%86%A0%EB%B9%84-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EC%9D%B4%ED%95%B4%EC%99%80%EC%9B%90%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.inflearn.com/course/%ED%86%A0%EB%B9%84-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EC%9D%B4%ED%95%B4%EC%99%80%EC%9B%90%EB%A6%AC&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/d0csZo/hyUkk4Rigg/8i5O5O5qs6uUZkq68Weio1/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/cNMQi3/hyUnNxu2DR/QCbB7x6FEiK91ZB50GN5t1/img.png?width=1200&amp;amp;height=781&amp;amp;face=0_0_1200_781,https://scrap.kakaocdn.net/dn/ydccr/hyUnQA0C7n/3TpU7z6qwu9sKQIkkbGGTK/img.png?width=1200&amp;amp;height=770&amp;amp;face=489_594_556_667');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;토비의 스프링 부트 - 이해와 원리 - 인프런 | 강의&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;스프링 부트의 핵심 기능을 직접 만들어보면서 스프링 부트의 동작 원리를 이해하고, 이를 통해 스프링 부트를 잘 학습하고 사용하는 방법을 배우는 강의입니다. 스프링 부트가 사용하는 스프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.inflearn.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://inpa.tistory.com/entry/JAVA-%E2%98%95-JVM-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%98%81%EC%97%AD-%EC%8B%AC%ED%99%94%ED%8E%B8&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://inpa.tistory.com/entry/JAVA-%E2%98%95-JVM-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%98%81%EC%97%AD-%EC%8B%AC%ED%99%94%ED%8E%B8&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1698675894991&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;☕ JVM 내부 구조 &amp;amp; 메모리 영역   총정리&quot; data-og-description=&quot;저번 포스팅에서는 JRE / JDK / JVM에 대해서 간략하게 알아보는 시간을 가졌다면, 이번 포스팅에서는 JVM의 내부 구조에 대해 좀 더 자세하게 알아보도록 할 예정이다. JVM(자바 가상 머신)은 자바 언&quot; data-og-host=&quot;inpa.tistory.com&quot; data-og-source-url=&quot;https://inpa.tistory.com/entry/JAVA-%E2%98%95-JVM-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%98%81%EC%97%AD-%EC%8B%AC%ED%99%94%ED%8E%B8&quot; data-og-url=&quot;https://inpa.tistory.com/entry/JAVA-%E2%98%95-JVM-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%98%81%EC%97%AD-%EC%8B%AC%ED%99%94%ED%8E%B8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Tsy0u/hyUlrby3Ym/9rQID99LKZk4isonOK6rVK/img.png?width=800&amp;amp;height=473&amp;amp;face=0_0_800_473,https://scrap.kakaocdn.net/dn/bMrFMi/hyUnKAL6Es/Ob5DLmABQtVc3yxdQFZEkk/img.png?width=800&amp;amp;height=473&amp;amp;face=0_0_800_473,https://scrap.kakaocdn.net/dn/binuP6/hyUkanCmPY/NwjpRxbyMVC0CI4nHTlIkK/img.png?width=896&amp;amp;height=527&amp;amp;face=0_0_896_527&quot;&gt;&lt;a href=&quot;https://inpa.tistory.com/entry/JAVA-%E2%98%95-JVM-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%98%81%EC%97%AD-%EC%8B%AC%ED%99%94%ED%8E%B8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inpa.tistory.com/entry/JAVA-%E2%98%95-JVM-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%98%81%EC%97%AD-%EC%8B%AC%ED%99%94%ED%8E%B8&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Tsy0u/hyUlrby3Ym/9rQID99LKZk4isonOK6rVK/img.png?width=800&amp;amp;height=473&amp;amp;face=0_0_800_473,https://scrap.kakaocdn.net/dn/bMrFMi/hyUnKAL6Es/Ob5DLmABQtVc3yxdQFZEkk/img.png?width=800&amp;amp;height=473&amp;amp;face=0_0_800_473,https://scrap.kakaocdn.net/dn/binuP6/hyUkanCmPY/NwjpRxbyMVC0CI4nHTlIkK/img.png?width=896&amp;amp;height=527&amp;amp;face=0_0_896_527');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;☕ JVM 내부 구조 &amp;amp; 메모리 영역   총정리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;저번 포스팅에서는 JRE / JDK / JVM에 대해서 간략하게 알아보는 시간을 가졌다면, 이번 포스팅에서는 JVM의 내부 구조에 대해 좀 더 자세하게 알아보도록 할 예정이다. JVM(자바 가상 머신)은 자바 언&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;inpa.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://inpa.tistory.com/entry/JAVA-%E2%98%95-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%8A%94-%EC%96%B8%EC%A0%9C-%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%97%90-%EB%A1%9C%EB%94%A9-%EC%B4%88%EA%B8%B0%ED%99%94-%EB%90%98%EB%8A%94%EA%B0%80-%E2%9D%93#recentComments&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://inpa.tistory.com/entry/JAVA-%E2%98%95-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%8A%94-%EC%96%B8%EC%A0%9C-%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%97%90-%EB%A1%9C%EB%94%A9-%EC%B4%88%EA%B8%B0%ED%99%94-%EB%90%98%EB%8A%94%EA%B0%80-%E2%9D%93#recentComments&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1698672546390&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;☕ 클래스는 언제 메모리에 로딩 &amp;amp; 초기화 되는가 ❓&quot; data-og-description=&quot;JVM의 클래스 로더 (Class Loader) 자바의 클래스들이 언제 어디서 메모리에 올라가고 클래스 멤버들이 초기화되는지, 원리를 알기위해선 우선 JVM(자바 가상 머신)의 클래스 로더(Class Loader)의 진행 &quot; data-og-host=&quot;inpa.tistory.com&quot; data-og-source-url=&quot;https://inpa.tistory.com/entry/JAVA-%E2%98%95-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%8A%94-%EC%96%B8%EC%A0%9C-%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%97%90-%EB%A1%9C%EB%94%A9-%EC%B4%88%EA%B8%B0%ED%99%94-%EB%90%98%EB%8A%94%EA%B0%80-%E2%9D%93#recentComments&quot; data-og-url=&quot;https://inpa.tistory.com/entry/JAVA-%E2%98%95-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%8A%94-%EC%96%B8%EC%A0%9C-%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%97%90-%EB%A1%9C%EB%94%A9-%EC%B4%88%EA%B8%B0%ED%99%94-%EB%90%98%EB%8A%94%EA%B0%80-%E2%9D%93&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bUpkFn/hyUnQ113VJ/mtKXVgKWex9qp5gTUFpaW0/img.png?width=800&amp;amp;height=417&amp;amp;face=0_0_800_417,https://scrap.kakaocdn.net/dn/cjOlap/hyUltNWCuR/qx6GoKO1aA3UHzqbVTiWgK/img.png?width=800&amp;amp;height=417&amp;amp;face=0_0_800_417,https://scrap.kakaocdn.net/dn/bqUWX8/hyUluTBCpV/mJmy5ruWUM67ppVW8E1SFK/img.png?width=820&amp;amp;height=388&amp;amp;face=0_0_820_388&quot;&gt;&lt;a href=&quot;https://inpa.tistory.com/entry/JAVA-%E2%98%95-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%8A%94-%EC%96%B8%EC%A0%9C-%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%97%90-%EB%A1%9C%EB%94%A9-%EC%B4%88%EA%B8%B0%ED%99%94-%EB%90%98%EB%8A%94%EA%B0%80-%E2%9D%93#recentComments&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inpa.tistory.com/entry/JAVA-%E2%98%95-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%8A%94-%EC%96%B8%EC%A0%9C-%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%97%90-%EB%A1%9C%EB%94%A9-%EC%B4%88%EA%B8%B0%ED%99%94-%EB%90%98%EB%8A%94%EA%B0%80-%E2%9D%93#recentComments&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bUpkFn/hyUnQ113VJ/mtKXVgKWex9qp5gTUFpaW0/img.png?width=800&amp;amp;height=417&amp;amp;face=0_0_800_417,https://scrap.kakaocdn.net/dn/cjOlap/hyUltNWCuR/qx6GoKO1aA3UHzqbVTiWgK/img.png?width=800&amp;amp;height=417&amp;amp;face=0_0_800_417,https://scrap.kakaocdn.net/dn/bqUWX8/hyUluTBCpV/mJmy5ruWUM67ppVW8E1SFK/img.png?width=820&amp;amp;height=388&amp;amp;face=0_0_820_388');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;☕ 클래스는 언제 메모리에 로딩 &amp;amp; 초기화 되는가 ❓&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;JVM의 클래스 로더 (Class Loader) 자바의 클래스들이 언제 어디서 메모리에 올라가고 클래스 멤버들이 초기화되는지, 원리를 알기위해선 우선 JVM(자바 가상 머신)의 클래스 로더(Class Loader)의 진행&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;inpa.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=2G41JMLh05U&quot;&gt;https://www.youtube.com/watch?v=2G41JMLh05U&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=2G41JMLh05U&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/tYP2g/hyUj9Ce7OQ/mbsNZWlAgQdtEUfg9ilzAk/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/2G41JMLh05U&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JAVA</category>
      <category>(static) Outer class</category>
      <category>Inner Class</category>
      <category>jvm</category>
      <category>method area</category>
      <category>Nested class</category>
      <category>Outer Class</category>
      <category>Spring Bean</category>
      <category>Static</category>
      <author>fadet</author>
      <guid isPermaLink="true">https://fadet-coding.tistory.com/90</guid>
      <comments>https://fadet-coding.tistory.com/90#entry90comment</comments>
      <pubDate>Mon, 30 Oct 2023 23:27:29 +0900</pubDate>
    </item>
    <item>
      <title>(내가 방치했던)토이 프로젝트 되살리기</title>
      <link>https://fadet-coding.tistory.com/89</link>
      <description>&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;*&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;이 포스트는 학습 과정에서 그 내용을 기록한 글이기에 부정확한 정보가 포함될 수 있습니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;따라서 해당 글은 참고용으로만 봐주시고 틀린 부분이 있다면 알려주시면 감사하겠습니다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 이 글은 &lt;a href=&quot;https://github.com/kth1017/project_GptApi_1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/kth1017/project_GptApi_1&lt;/a&gt; 에 올린 토이 프로젝트에 관한 내용입니다. 더 자세히 알고 싶으시다면 아직 포스팅이 덜 끝났지만 블로그에 포스팅된&amp;nbsp;&lt;a style=&quot;text-align: start;&quot; href=&quot;https://fadet-coding.tistory.com/75&quot;&gt;&lt;b&gt;P3_GPT API로 프로그래밍 AI 웹서비스 만들어보기&lt;/b&gt;&lt;/a&gt; 시리즈를 참고해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런저런 이유로 최근에야 방치했던 토이 프로젝트에 문제가 발생한 것을 깨달았습니다. 정말 개발자를 지망한다는 사람치곤 자격이 있는지 의심스럽지만 그래도 솔직하게 털어놓고 해결하는 포스트를 올리는 것이 맞겠.... 죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 토이 프로젝트에 기재된 url에 들어가서 질문을 해보면&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1831&quot; data-origin-height=&quot;703&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HwAqX/btsuegTUxWh/KiZ5pBfUrekI4f7OgG01Jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HwAqX/btsuegTUxWh/KiZ5pBfUrekI4f7OgG01Jk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HwAqX/btsuegTUxWh/KiZ5pBfUrekI4f7OgG01Jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHwAqX%2FbtsuegTUxWh%2FKiZ5pBfUrekI4f7OgG01Jk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;391&quot; height=&quot;150&quot; data-origin-width=&quot;1831&quot; data-origin-height=&quot;703&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 걸어놨던 요청 리밋이 걸리면서 서비스가 되지 않습니다. 우선 이것을 보면 뭔가 api 수신에서 문제가 생긴 것 같아 서버 DB를 열어봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB에서 answer 테이블을 열어보니 아래와 같이 떴습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1733&quot; data-origin-height=&quot;471&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jwfed/btsueL0DZbr/cEHKvfnMrTNtvheyrj9Dnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jwfed/btsueL0DZbr/cEHKvfnMrTNtvheyrj9Dnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jwfed/btsueL0DZbr/cEHKvfnMrTNtvheyrj9Dnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJwfed%2FbtsueL0DZbr%2FcEHKvfnMrTNtvheyrj9Dnk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;522&quot; height=&quot;142&quot; data-origin-width=&quot;1733&quot; data-origin-height=&quot;471&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 보고 바로 '아 api 사용 정책이 바꼈나보다. 하긴 유료로 바뀔만하긴 했지'였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이것저것 찾아본 결과&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1246&quot; data-origin-height=&quot;295&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCqwuT/btst7xoS5o0/yH2uQoXkKDJIOz9Ammedy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCqwuT/btst7xoS5o0/yH2uQoXkKDJIOz9Ammedy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCqwuT/btst7xoS5o0/yH2uQoXkKDJIOz9Ammedy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCqwuT%2Fbtst7xoS5o0%2FyH2uQoXkKDJIOz9Ammedy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1246&quot; height=&quot;295&quot; data-origin-width=&quot;1246&quot; data-origin-height=&quot;295&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 단순히 무료 크레딧이 6월 1일날 만료되서 먹통이 된거였네요. 찾아보니 무료 크레딧은 가입 후 3개월 뒤에 만료된다고 합니다. 이것으로 알 수 있었던 건 '기간안에 무료 크레딧을 다 쓸 만큼의 트래픽도 발생하지 않았구나'였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어찌됐든 서비스를 정상화해야하니 무료 api를 제공하는 다른 대화형 인공지능을 찾아볼까하다가 큰 금액이 아니고 한 번 결제해두면 1년 동안 사용한다고해서 그냥 크레딧을 결제했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1163&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3vooy/btst7SGlXFg/vhVtKCnGmqzG69TKkteVuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3vooy/btst7SGlXFg/vhVtKCnGmqzG69TKkteVuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3vooy/btst7SGlXFg/vhVtKCnGmqzG69TKkteVuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3vooy%2Fbtst7SGlXFg%2FvhVtKCnGmqzG69TKkteVuk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;472&quot; height=&quot;197&quot; data-origin-width=&quot;1163&quot; data-origin-height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결제 방법은 크게 어렵지 않으실텐데 한 가지 중요한건 바로 limit 설정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메뉴에서 usage limit가시면 아래와 같이 뜨실텐데 soft limit과 hard limit만 수정해서 저장해주시면 됩니다. default가 120달러라 만약 api 키가 노출이라도 되면 졸지에 15만원 나갈 수도 있으니 주의.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1008&quot; data-origin-height=&quot;652&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zwdhh/btst6jYJVpE/tLaP9ReZakX1ayEgc6bH2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zwdhh/btst6jYJVpE/tLaP9ReZakX1ayEgc6bH2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zwdhh/btst6jYJVpE/tLaP9ReZakX1ayEgc6bH2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZwdhh%2Fbtst6jYJVpE%2FtLaP9ReZakX1ayEgc6bH2K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1008&quot; height=&quot;652&quot; data-origin-width=&quot;1008&quot; data-origin-height=&quot;652&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이거 설정하면 다시 사이트는 정상 작동합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1759&quot; data-origin-height=&quot;579&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwQcem/btsudj4BoHZ/OMAbK6x9OJFmdBGkxkjzQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwQcem/btsudj4BoHZ/OMAbK6x9OJFmdBGkxkjzQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwQcem/btsudj4BoHZ/OMAbK6x9OJFmdBGkxkjzQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwQcem%2Fbtsudj4BoHZ%2FOMAbK6x9OJFmdBGkxkjzQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;571&quot; height=&quot;188&quot; data-origin-width=&quot;1759&quot; data-origin-height=&quot;579&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;P.S. 이거 만지다가 하나 새로 안 게 &lt;b&gt;절대 DB에서 table을 drop하면 안된다&lt;/b&gt;입니다. 전에 업데이트해서 drop하면 휴지통 간다는 글 언뜻보고 그냥 drop했다가 &lt;b&gt;그건 oracle 한정 ㅋ&amp;nbsp;&lt;/b&gt;을 다시 알고 DB에 쿼리 입력해서 테이블 다시 만들었습니다. 덕분에 SQL문 foreign key 복습했으니 오히려 좋아인가요?&lt;/p&gt;</description>
      <category>Debug</category>
      <category>gpt api 사용량</category>
      <category>gpt api 크레딧</category>
      <category>openai 크레딧</category>
      <author>fadet</author>
      <guid isPermaLink="true">https://fadet-coding.tistory.com/89</guid>
      <comments>https://fadet-coding.tistory.com/89#entry89comment</comments>
      <pubDate>Sat, 16 Sep 2023 23:25:01 +0900</pubDate>
    </item>
  </channel>
</rss>