<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발자 미연</title>
    <link>https://dev-miyeon.tistory.com/</link>
    <description>DevOps &amp;amp; Backend Insights | By Miyeon</description>
    <language>ko</language>
    <pubDate>Wed, 13 May 2026 07:20:55 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>422haha</managingEditor>
    <image>
      <title>개발자 미연</title>
      <url>https://tistory1.daumcdn.net/tistory/7381032/attach/24b8682d0d1e49cca4c4ae23dc8b38ea</url>
      <link>https://dev-miyeon.tistory.com</link>
    </image>
    <item>
      <title>시나공 빅데이터분석기사 실기 Python 교재 리뷰: 시나공 Python 교재 첫인상과 학습 계획</title>
      <link>https://dev-miyeon.tistory.com/11</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요! 이번 포스팅에서는 &lt;b&gt;빅데이터분석기사 실기&lt;/b&gt; 시험을 준비하며 활용 중인 &lt;b&gt;시나공 Python 교재&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;3000&quot; data-origin-height=&quot;4000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dzjq6/btsOmjQwoSw/bYs9bsAsZpnbZpCcryIr51/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dzjq6/btsOmjQwoSw/bYs9bsAsZpnbZpCcryIr51/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dzjq6/btsOmjQwoSw/bYs9bsAsZpnbZpCcryIr51/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDzjq6%2FbtsOmjQwoSw%2FbYs9bsAsZpnbZpCcryIr51%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;3000&quot; height=&quot;4000&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/phZBB/btsOmgsINdd/u5mThVqCZKwghWk8IbqEK1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/phZBB/btsOmgsINdd/u5mThVqCZKwghWk8IbqEK1/img.jpg&quot; width=&quot;100%&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;292&quot; data-is-animation=&quot;false&quot; style=&quot;width: 43.5327%; margin-right: 10px;&quot; data-widthpercent=&quot;44.04&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/phZBB/btsOmgsINdd/u5mThVqCZKwghWk8IbqEK1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FphZBB%2FbtsOmgsINdd%2Fu5mThVqCZKwghWk8IbqEK1%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;498&quot; height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIDKAm/btsOlGr6uew/rX4efGybN463Z1tVXrvwW0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIDKAm/btsOlGr6uew/rX4efGybN463Z1tVXrvwW0/img.jpg&quot; width=&quot;100%&quot; data-origin-width=&quot;611&quot; data-origin-height=&quot;282&quot; data-is-animation=&quot;false&quot; style=&quot;width: 55.3045%;&quot; data-widthpercent=&quot;55.96&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIDKAm/btsOlGr6uew/rX4efGybN463Z1tVXrvwW0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIDKAm%2FbtsOlGr6uew%2FrX4efGybN463Z1tVXrvwW0%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;611&quot; height=&quot;282&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 데이터 분석 역량을 강화하고, 취업 시장에서 경쟁력을 높이기 위해 빅데이터분석기사 자격증을 준비하고 있습니다. 이 자격증은 &lt;b&gt;국가공인 자격&lt;/b&gt;으로, 실무 중심의 코딩 역량과 데이터 분석 능력을 종합적으로 평가합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순한 개념 암기형 시험이 아니라 실제 데이터를 다루고 문제를 해결하는 능력이 요구되기 때문에, &lt;b&gt;데이터 기반 사고력과 실전 감각을 함께 키울 수 있는 기회&lt;/b&gt;라고 판단하여 도전하게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 이 자격증은 &lt;b&gt;데이터 분석 전문가로서의 전문성과 신뢰성을 공식적으로 입증할 수 있는 수단&lt;/b&gt;이기도 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기업의 데이터 기반 의사결정에 기여할 수 있는 인재로 성장하고자, 실력을 쌓기 위한 준비를 본격적으로 시작했습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;학습 방향이 막막했을 때 도움이 된 시나공&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실기 시험을 처음 준비하면서 가장 막막했던 부분은 &lt;b&gt;무엇부터 시작해야 할지 전혀 감이 잡히지 않았다는 점&lt;/b&gt;이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험 유형도 낯설고, 어떤 문제들이 출제되는지조차 알기 어려웠던 상황에서 &lt;b&gt;시나공 빅데이터분석기사 실기 교재&lt;/b&gt;는 훌륭한 출발점이 되어주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 이론만 나열하는 구성이 아니라, &lt;b&gt;작업형 1, 2, 3 유형별로 어떻게 접근해야 하는지를 명확하게 안내해 주어&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;3000&quot; data-origin-height=&quot;4000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/conl8q/btsOkOkcCjE/lyk8QQM5QcVUDRpYLaMA31/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/conl8q/btsOkOkcCjE/lyk8QQM5QcVUDRpYLaMA31/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/conl8q/btsOkOkcCjE/lyk8QQM5QcVUDRpYLaMA31/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fconl8q%2FbtsOkOkcCjE%2Flyk8QQM5QcVUDRpYLaMA31%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;3000&quot; height=&quot;4000&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2주 단기 집중 루틴으로 학습&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험까지 여유가 많지 않은 만큼, 아래와 같은 일정으로 &lt;b&gt;2주간 집중 학습 루틴&lt;/b&gt;을 계획하고 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1주차&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작업형 1, 2, 3 유형별 개념 구조 정리&lt;/li&gt;
&lt;li&gt;pandas, seaborn, 머신러닝 기본 문법 복습&lt;/li&gt;
&lt;li&gt;확인문제와 실습을 병행하며 흐름 익히기&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2주차&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시문제 및 기출 문제 반복 풀이&lt;/li&gt;
&lt;li&gt;오답 정리 및 시간 안배 연습&lt;/li&gt;
&lt;li&gt;작업형 3 집중 학습 (모델 구현 및 평가 중심)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 루틴은 시나공 교재의 구성과도 잘 맞습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;개념 &amp;rarr; 확인문제 &amp;rarr; 예시문제 &amp;rarr; 최신 기출 문제&lt;/b&gt;로 이어지는 흐름이 자연스럽고, 반복 학습을 유도해 실전 감각을 빠르게 끌어올리는 데 효과적이라고 느꼈습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfEcu4/btsOkLVyiPi/ELKTrg2t1sJeWH5mnSCoTK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfEcu4/btsOkLVyiPi/ELKTrg2t1sJeWH5mnSCoTK/img.jpg&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;3000&quot; data-is-animation=&quot;false&quot; data-filename=&quot;빅분기실기_개념.jpg&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfEcu4/btsOkLVyiPi/ELKTrg2t1sJeWH5mnSCoTK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfEcu4%2FbtsOkLVyiPi%2FELKTrg2t1sJeWH5mnSCoTK%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;4000&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/drbZkD/btsOlGMqSWP/CXJ4iFz14LlHxe8o5HGNBk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/drbZkD/btsOlGMqSWP/CXJ4iFz14LlHxe8o5HGNBk/img.jpg&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;3000&quot; data-is-animation=&quot;false&quot; data-filename=&quot;빅분기실기_확인문제.jpg&quot; data-widthpercent=&quot;50&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/drbZkD/btsOlGMqSWP/CXJ4iFz14LlHxe8o5HGNBk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdrbZkD%2FbtsOlGMqSWP%2FCXJ4iFz14LlHxe8o5HGNBk%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;4000&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0rmgJ/btsOlbMWUkj/VO4qkVrxn0A4oUBjqXlcN0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0rmgJ/btsOlbMWUkj/VO4qkVrxn0A4oUBjqXlcN0/img.jpg&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;3000&quot; data-is-animation=&quot;false&quot; data-filename=&quot;빅분기실기_예시문제.jpg&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0rmgJ/btsOlbMWUkj/VO4qkVrxn0A4oUBjqXlcN0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0rmgJ%2FbtsOlbMWUkj%2FVO4qkVrxn0A4oUBjqXlcN0%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;4000&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjQiAS/btsOlEuiphC/grsZyjBbgtPUdxDYKNtyc0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjQiAS/btsOlEuiphC/grsZyjBbgtPUdxDYKNtyc0/img.jpg&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;3000&quot; data-is-animation=&quot;false&quot; data-filename=&quot;빅분기실기_최신 기출 문제.jpg&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjQiAS/btsOlEuiphC/grsZyjBbgtPUdxDYKNtyc0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjQiAS%2FbtsOlEuiphC%2FgrsZyjBbgtPUdxDYKNtyc0%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;4000&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시나공 빅데이터분석기사 실기 Python의 장점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;입문자도 따라가기 쉬운 설명 방식&lt;/b&gt;&lt;br /&gt;Python 문법이 익숙하지 않은 경우에도, 코드 흐름을 자연스럽게 따라갈 수 있도록 구성되어 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;작업형 유형별 전략 제시&lt;/b&gt;&lt;br /&gt;유형별 접근법이 명확하게 정리되어 있어, 학습 방향을 설정하는 데 큰 도움이 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;셀 단위 실행 결과 확인&lt;/b&gt;&lt;br /&gt;코드를 직접 실행해보며 셀 단위로 결과를 확인할 수 있어, 실습 기반 학습과 실전 대비에 효과적이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;최신 기출 경향 반영&lt;/b&gt;&lt;br /&gt;최근 4개년 기출 문제가 수록되어 있어 출제 경향을 파악하고 실제 시험을 대비하는 데 도움이 되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;빅분기실기_최근 4개년 기출 문제.jpg&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpNCNo/btsOms7JuD7/KlOXKKzLnzPsKFIh2YEo41/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpNCNo/btsOms7JuD7/KlOXKKzLnzPsKFIh2YEo41/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpNCNo/btsOms7JuD7/KlOXKKzLnzPsKFIh2YEo41/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpNCNo%2FbtsOms7JuD7%2FKlOXKKzLnzPsKFIh2YEo41%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;4000&quot; height=&quot;3000&quot; data-filename=&quot;빅분기실기_최근 4개년 기출 문제.jpg&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;3000&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 실기 시험은 치르지 않았지만, 그 전 단계에서 &lt;b&gt;학습 흐름을 정리하고 실전 준비의 기반을 마련하는데 &lt;/b&gt;시나공 교재가 큰 도움이 되었습니다. 혼자 준비하는 입장에서도 학습 방향을 명확히 설정할 수 있었고, 앞으로 2주 동안 이 교재를 중심으로 전략적인 학습을 이어갈 예정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터 분석 실력을 체계적으로 정리하고 자격증으로 역량을 입증하고자 한다면&lt;/b&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;i&gt;본 포스팅은 업체로부터 제품을 제공받아 학습 후 솔직한 후기를 작성했습니다. &lt;/i&gt;&lt;/p&gt;</description>
      <category>자격증</category>
      <category>데이터분석공부</category>
      <category>데이터분석기사실기독학</category>
      <category>빅데이터분석기사</category>
      <category>빅데이터분석기사실기</category>
      <category>빅데이터분석기사실기책</category>
      <category>빅데이터자격증</category>
      <category>시나공교재후기</category>
      <category>시나공빅데이터분석기사</category>
      <category>자격증독학</category>
      <category>파이썬데이터분석</category>
      <author>422haha</author>
      <guid isPermaLink="true">https://dev-miyeon.tistory.com/11</guid>
      <comments>https://dev-miyeon.tistory.com/11#entry11comment</comments>
      <pubDate>Sat, 31 May 2025 21:09:16 +0900</pubDate>
    </item>
    <item>
      <title>데이터에듀 2025 ADsP 민트책 리뷰: 데이터분석 준전문가 합격을 위한 교재 선택 가이드</title>
      <link>https://dev-miyeon.tistory.com/9</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요! 이번 포스팅에서는 데이터 분석 준전문가(ADsP) 자격증을 준비하며 사용 중인 &lt;b&gt;데이터에듀 2025 ADsP 민트책&lt;/b&gt;에 대한 학습 후기와 인상을 공유하려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ADsP는 데이터 분석 분야의 입문 단계에서 많이 선택하는 자격증입니다. 저 역시 체계적인 공부를 위해 어떤 교재를 사용할지 고민하다가 이 민트색 교재를 선택하게 되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lu6Ra/btsNwJKFnJW/rDxKlwPwE4f0c1fdmKaxX1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lu6Ra/btsNwJKFnJW/rDxKlwPwE4f0c1fdmKaxX1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lu6Ra/btsNwJKFnJW/rDxKlwPwE4f0c1fdmKaxX1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flu6Ra%2FbtsNwJKFnJW%2FrDxKlwPwE4f0c1fdmKaxX1%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;4000&quot; height=&quot;3000&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;3000&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;데이터에듀 2025 ADsP 민트책의 장점&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 최신 출제 경향 반영&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10년 연속 ADsP 베스트셀러라는 타이틀답게, 한국데이터베이스진흥원의 공식 가이드를 기반으로 최근 기출 트렌드를 잘 반영하고 있습니다.&lt;br /&gt;개념 설명이 단순 나열이 아닌 &lt;b&gt;시험에 나올 수 있는 방식&lt;/b&gt;으로 구성되어 있어 읽는 흐름이 매우 자연스럽습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 풍부한 문제 구성과 명쾌한 해설&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;총 &lt;b&gt;1,311문제&lt;/b&gt;가 수록되어 있는데요, 기출 복원 문제, 모의고사, 개념 체크 문제가 다양하게 구성되어 있어 반복 학습이 가능합니다.&lt;br /&gt;특히 절마다 핵심 요약 &amp;rarr; 문제 풀이 순서가 이어져서 학습 리듬을 유지하기 좋았습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20250422_114814705_08.jpg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8QxRY/btsNx1pr5qC/kHb3VNfKNmFSG1Q3D8c4IK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8QxRY/btsNx1pr5qC/kHb3VNfKNmFSG1Q3D8c4IK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8QxRY/btsNx1pr5qC/kHb3VNfKNmFSG1Q3D8c4IK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8QxRY%2FbtsNx1pr5qC%2FkHb3VNfKNmFSG1Q3D8c4IK%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;3000&quot; height=&quot;4000&quot; data-filename=&quot;KakaoTalk_20250422_114814705_08.jpg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 모바일 앱을 통한 자투리 학습&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;QR 코드를 찍으면 연결되는 앱 &lt;b&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=dataedupt.app&quot;&gt;데이터에듀PT&lt;/a&gt;&lt;/b&gt; 은 학습 효율을 높이는 데 큰 도움이 됐습니다.&lt;br /&gt;이론정복강의는 총 16시간 분량인데, 절마다 짧게 끊어져 있어 &lt;b&gt;자투리 시간&lt;/b&gt;에 빠르게 개념을 정리할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTjEQG/btsNxj5atMu/uRR6G1rPgOZTdOGO85AuGK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTjEQG/btsNxj5atMu/uRR6G1rPgOZTdOGO85AuGK/img.jpg&quot; width=&quot;100%&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot; style=&quot;width: 32.528%; margin-right: 10px;&quot; data-widthpercent=&quot;33.3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTjEQG/btsNxj5atMu/uRR6G1rPgOZTdOGO85AuGK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTjEQG%2FbtsNxj5atMu%2FuRR6G1rPgOZTdOGO85AuGK%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;3000&quot; height=&quot;4000&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfnseo/btsNw6LJ3GI/ExKG5IHNVH1VScJT18Z8Vk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfnseo/btsNw6LJ3GI/ExKG5IHNVH1VScJT18Z8Vk/img.jpg&quot; width=&quot;100%&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1438&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5732%; margin-right: 10px;&quot; data-widthpercent=&quot;33.35&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfnseo/btsNw6LJ3GI/ExKG5IHNVH1VScJT18Z8Vk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcfnseo%2FbtsNw6LJ3GI%2FExKG5IHNVH1VScJT18Z8Vk%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;1080&quot; height=&quot;1438&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NkWs0/btsNxYzqH1o/sKA4iv9pM60Ip7C7MUOMJ1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NkWs0/btsNxYzqH1o/sKA4iv9pM60Ip7C7MUOMJ1/img.jpg&quot; width=&quot;100%&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1438&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5732%;&quot; data-widthpercent=&quot;33.35&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NkWs0/btsNxYzqH1o/sKA4iv9pM60Ip7C7MUOMJ1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNkWs0%2FbtsNxYzqH1o%2FsKA4iv9pM60Ip7C7MUOMJ1%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;1080&quot; height=&quot;1438&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 해설 봇인 &lt;b&gt;비기봇&lt;/b&gt;을 통해 잘 이해되지 않았던 문제에 대한 해설도 바로 확인할 수 있어서 개인적으로 정말 만족하고 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 시험 직전 요약용 'D-7 합격마법노트'&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 본격적인 마무리 학습 단계는 아니지만, 부록으로 제공되는 &lt;b&gt;합격마법노트&lt;/b&gt;를 미리 살펴보았는데요, 시험 전 7일 동안 회독하기 좋게 구성이 되어 있어 벌써부터 기대가 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t5n7D/btsNw7xdDBv/YRazk1UWEbOISSaDFzT3o1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t5n7D/btsNw7xdDBv/YRazk1UWEbOISSaDFzT3o1/img.jpg&quot; width=&quot;100%&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t5n7D/btsNw7xdDBv/YRazk1UWEbOISSaDFzT3o1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft5n7D%2FbtsNw7xdDBv%2FYRazk1UWEbOISSaDFzT3o1%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;3000&quot; height=&quot;4000&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3PLTb/btsNwJqkFln/6GQ2CdZfksuEur0V5wSWD0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3PLTb/btsNwJqkFln/6GQ2CdZfksuEur0V5wSWD0/img.jpg&quot; width=&quot;100%&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3PLTb/btsNwJqkFln/6GQ2CdZfksuEur0V5wSWD0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3PLTb%2FbtsNwJqkFln%2F6GQ2CdZfksuEur0V5wSWD0%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;3000&quot; height=&quot;4000&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bptKV1/btsNxTLEGX1/YfGppsUAIYPPcyTGFa0kl1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bptKV1/btsNxTLEGX1/YfGppsUAIYPPcyTGFa0kl1/img.jpg&quot; width=&quot;100%&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bptKV1/btsNxTLEGX1/YfGppsUAIYPPcyTGFa0kl1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbptKV1%2FbtsNxTLEGX1%2FYfGppsUAIYPPcyTGFa0kl1%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;3000&quot; height=&quot;4000&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 설치 없는 웹 기반 R 실습&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;R 실습도 별도 설치 없이 가능한 웹 기반 환경 &lt;b&gt;&lt;a href=&quot;https://www.dataedu.kr/codelearning/&quot;&gt;코드러닝&lt;/a&gt;&lt;/b&gt; 을 통해 부담 없이 연습할 수 있었습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;추천 학습 루틴&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 현재 아래와 같은 루틴으로 이 교재를 활용하며 학습을 진행하고 있습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하루 한 절씩 개념을 읽고 QR 강의 시청&lt;/li&gt;
&lt;li&gt;이어서 같은 절의 문제를 풀며 이해도를 점검&lt;/li&gt;
&lt;li&gt;주말에는 모의고사 한 회분을 풀고, 오답 체크&lt;/li&gt;
&lt;li&gt;시험 1주일 전부터는 합격마법노트 중심으로 복습 예정&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 시험을 치르기 전이지만, &lt;b&gt;현재까지의 학습 만족도는 매우 높습니다.&lt;/b&gt;&lt;br /&gt;개념 설명, 문제 구성, 모바일 학습 환경까지 전반적으로 잘 설계된 교재라고 느껴졌습니다.&lt;br /&gt;특히 시간을 효율적으로 쓰고 싶은 분들에게 추천드릴 만한 책입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ADsP 시험을 준비하시는 분들께 도움이 되었길 바라며, 저도 열심히 공부해서 좋은 결과로 이어지길 기대해봅니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;이 서평은 데이터에듀로부터 도서를 제공받아 작성된 솔직한 후기입니다.&lt;/i&gt;&lt;/p&gt;</description>
      <category>자격증</category>
      <category>ADsP</category>
      <category>ADsP교재</category>
      <category>데이터분석자격증</category>
      <category>데이터분석준전문가</category>
      <category>데이터에듀</category>
      <category>데이터에듀pt</category>
      <category>민트책</category>
      <category>자격증공부</category>
      <category>코드러닝</category>
      <category>한국데이터산업진흥원</category>
      <author>422haha</author>
      <guid isPermaLink="true">https://dev-miyeon.tistory.com/9</guid>
      <comments>https://dev-miyeon.tistory.com/9#entry9comment</comments>
      <pubDate>Thu, 24 Apr 2025 10:45:59 +0900</pubDate>
    </item>
    <item>
      <title>Git Merge, Rebase, Squash: 차이점과 적합한 사용 사례 비교</title>
      <link>https://dev-miyeon.tistory.com/8</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요! 이번 포스팅에서는 &lt;b&gt;Git의 Merge, Rebase, Squash&lt;/b&gt;라는 세 가지 주요 기능을 비교하고, 각각의 적합한 상황에 대해 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Git은 강력한 버전 관리 도구로, 브랜치 전략과 히스토리 관리가 중요한 협업 환경에서 큰 역할을 합니다. 이 글을 통해 &lt;b&gt;Merge, Rebase, Squash&lt;/b&gt;의 차이점을 명확히 이해하고, 프로젝트에 맞는 전략을 선택하는 데 도움을 드리고자 합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#1-merge%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80&quot;&gt;Merge란 무엇인가?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#2-rebase%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80&quot;&gt;Rebase란 무엇인가?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#3-squash%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80&quot;&gt;Squash란 무엇인가?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#4-merge-rebase-squash-%EB%B9%84%EA%B5%90&quot;&gt;Merge, Rebase, Squash 비교&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#5-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%83%81%ED%99%A9%EC%97%90-%EB%94%B0%EB%A5%B8-%EC%84%A0%ED%83%9D-%EA%B0%80%EC%9D%B4%EB%93%9C&quot;&gt;프로젝트 상황에 따른 선택 가이드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#6-%EC%B5%9C%EC%A2%85-%EA%B2%B0%EB%A1%A0&quot;&gt;최종 결론&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;911&quot; data-origin-height=&quot;589&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s5WlF/btsLQS3wTgN/5kFHqxxirFw5NlUA8wPXeK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s5WlF/btsLQS3wTgN/5kFHqxxirFw5NlUA8wPXeK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s5WlF/btsLQS3wTgN/5kFHqxxirFw5NlUA8wPXeK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs5WlF%2FbtsLQS3wTgN%2F5kFHqxxirFw5NlUA8wPXeK%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;911&quot; height=&quot;589&quot; data-origin-width=&quot;911&quot; data-origin-height=&quot;589&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Merge란 무엇인가?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Merge&lt;/b&gt;는 두 개의 브랜치를 병합하여 새로운 커밋을 생성하는 방법입니다. 주로 기능 개발이 완료된 브랜치를 메인 브랜치에 병합할 때 사용됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;작업 브랜치 생성:&lt;/b&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;git checkout -b feature-branch&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;작업 완료 후 병합:&lt;/b&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;git checkout master
git merge feature-branch&lt;/code&gt;&lt;/pre&gt;
결과적으로 새로운 병합 커밋이 생성됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브랜치 히스토리를 그대로 유지하여 작업 내용을 명확히 파악 가능.&lt;/li&gt;
&lt;li&gt;협업 환경에서 충돌이 적고 간단하게 병합 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;병합 시마다 새로운 병합 커밋(Merge Commit)이 생성되어 히스토리가 복잡해질 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Rebase란 무엇인가?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Rebase&lt;/b&gt;는 브랜치의 베이스를 변경하여 히스토리를 재구성하는 방법입니다. 커밋들을 재정렬하여 병합 커밋 없이 깔끔한 히스토리를 유지합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;작업 브랜치 생성 및 작업:&lt;/b&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;git checkout -b feature-branch&lt;/code&gt;&lt;/pre&gt;
브랜치에서 커밋을 진행합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Rebase 실행:&lt;/b&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;git checkout master
git pull origin master
git checkout feature-branch
git rebase master&lt;/code&gt;&lt;/pre&gt;
이 과정에서 커밋 충돌이 발생할 수 있으며, 충돌 해결 후 &lt;code&gt;git rebase --continue&lt;/code&gt; 명령을 실행합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;히스토리를 선형으로 유지하여 가독성이 높아짐.&lt;/li&gt;
&lt;li&gt;협업 시 변경 사항이 명확히 드러남.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복잡한 충돌 해결 과정이 필요할 수 있으며, 잘못 사용할 경우 히스토리가 손상될 위험이 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Squash란 무엇인가?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Squash&lt;/b&gt;는 여러 개의 커밋을 하나로 합치는 방법으로, 병합 시점을 기준으로 이전 커밋들을 합쳐 새로운 단일 커밋을 생성합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;작업 완료 후 Squash 실행:&lt;/b&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;git rebase -i master&lt;/code&gt;&lt;/pre&gt;
이 명령으로 인터랙티브 모드가 열리면, 병합할 커밋 앞에 &lt;code&gt;squash&lt;/code&gt; 또는 &lt;code&gt;s&lt;/code&gt;를 지정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;새 커밋 메시지 작성:&lt;/b&gt;&lt;br /&gt;모든 병합된 커밋을 하나로 합친 후, 새로운 커밋 메시지를 작성합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;불필요한 커밋을 제거하여 깔끔한 히스토리 유지.&lt;/li&gt;
&lt;li&gt;작은 커밋을 다수 포함한 브랜치를 병합할 때 유용.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커밋 히스토리가 단순화되면서 세부 변경 사항을 추적하기 어려움.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Merge, Rebase, Squash 비교&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;th&gt;장점&lt;/th&gt;
&lt;th&gt;단점&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Merge&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;두 브랜치를 병합하여 새 커밋 생성&lt;/td&gt;
&lt;td&gt;히스토리 유지, 충돌 관리 간단&lt;/td&gt;
&lt;td&gt;병합 커밋 증가로 히스토리 복잡&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Rebase&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;히스토리를 재정렬하여 병합 커밋 없음&lt;/td&gt;
&lt;td&gt;선형 히스토리, 가독성 향상&lt;/td&gt;
&lt;td&gt;충돌 해결이 복잡, 히스토리 손상 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Squash&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;여러 커밋을 하나로 합침&lt;/td&gt;
&lt;td&gt;깔끔한 히스토리, 작은 커밋 정리&lt;/td&gt;
&lt;td&gt;세부 변경 사항 추적 어려움&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 프로젝트 상황에 따른 선택 가이드&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Merge를 선택하세요:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;히스토리를 그대로 유지해야 하는 대규모 협업 프로젝트.&lt;/li&gt;
&lt;li&gt;각 작업의 진행 과정을 명확히 추적해야 하는 경우.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Rebase를 선택하세요:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선형 히스토리가 필요한 경우.&lt;/li&gt;
&lt;li&gt;병합 커밋 없이 깔끔한 히스토리를 유지하고 싶을 때.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Squash를 선택하세요:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다수의 작은 커밋을 하나로 정리하여 병합 시 깔끔한 히스토리가 필요한 경우.&lt;/li&gt;
&lt;li&gt;최종 병합 전 세부 작업 히스토리가 중요하지 않은 경우.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 최종 결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Merge, Rebase, Squash는 각각의 강점과 단점이 있습니다. 프로젝트 특성과 협업 방식에 따라 적절히 선택하는 것이 중요합니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Merge&lt;/b&gt;: 안정성과 히스토리 보존.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Rebase&lt;/b&gt;: 깔끔하고 선형적인 히스토리.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Squash&lt;/b&gt;: 불필요한 커밋 정리로 간결한 히스토리.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러분의 프로젝트 상황에 맞는 전략을 선택해 Git 히스토리를 더 효율적으로 관리해보세요!  &lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/doc&quot;&gt;Git 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Branching-Rebasing&quot;&gt;Rebase 사용 가이드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.atlassian.com/git/tutorials/merging-vs-rebasing&quot;&gt;Merge와 Rebase 비교&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다!&lt;/p&gt;</description>
      <category>Git</category>
      <category>GIT</category>
      <category>git merge</category>
      <category>git rebase</category>
      <category>git squash</category>
      <category>git 브랜치 전략</category>
      <category>git 사용법</category>
      <category>git 커밋 정리</category>
      <category>git 히스토리 관리</category>
      <category>버전 관리 도구</category>
      <category>협업 효율성</category>
      <author>422haha</author>
      <guid isPermaLink="true">https://dev-miyeon.tistory.com/8</guid>
      <comments>https://dev-miyeon.tistory.com/8#entry8comment</comments>
      <pubDate>Fri, 17 Jan 2025 17:12:22 +0900</pubDate>
    </item>
    <item>
      <title>Git Flow vs GitHub Flow vs GitLab Flow: 브랜치 전략의 차이점과 선택 가이드</title>
      <link>https://dev-miyeon.tistory.com/7</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요! 이번 포스팅에서는 &lt;b&gt;Git Flow&lt;/b&gt;, &lt;b&gt;GitHub Flow&lt;/b&gt;, &lt;b&gt;GitLab Flow&lt;/b&gt;라는 세 가지 대표적인 Git 브랜치 전략을 비교하고, 각 방식이 어떤 환경에 적합한지 살펴보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트의 규모와 개발 방식에 따라 적합한 브랜치 전략을 선택하면 협업 효율성과 릴리즈 속도를 크게 향상시킬 수 있습니다. 이 글을 통해 여러분의 프로젝트에 적합한 브랜치 전략을 선택하는 데 도움을 드리고자 합니다.&lt;/p&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#1-git-flow-%EA%B0%9C%EC%9A%94&quot;&gt;Git Flow 개요&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#2-github-flow-%EA%B0%9C%EC%9A%94&quot;&gt;GitHub Flow 개요&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#3-gitlab-flow-%EA%B0%9C%EC%9A%94&quot;&gt;GitLab Flow 개요&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#4-%EB%B8%8C%EB%9E%9C%EC%B9%98-%EC%A0%84%EB%9E%B5-%EB%B9%84%EA%B5%90&quot;&gt;브랜치 전략 비교&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#5-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%99%98%EA%B2%BD%EC%97%90-%EB%94%B0%EB%A5%B8-%EC%84%A0%ED%83%9D-%EA%B0%80%EC%9D%B4%EB%93%9C&quot;&gt;프로젝트 환경에 따른 선택 가이드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#6-%EC%B5%9C%EC%A2%85-%EA%B2%B0%EB%A1%A0&quot;&gt;최종 결론&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Git Flow 개요&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;1524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZzFkA/btsLJyct47q/LAZb3OoUSbg02NQnnaGlu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZzFkA/btsLJyct47q/LAZb3OoUSbg02NQnnaGlu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZzFkA/btsLJyct47q/LAZb3OoUSbg02NQnnaGlu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZzFkA%2FbtsLJyct47q%2FLAZb3OoUSbg02NQnnaGlu0%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;1150&quot; height=&quot;1524&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;1524&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Git Flow&lt;/b&gt;는 Vincent Driessen이 제안한 브랜칭 모델로, 복잡한 구조를 통해 대규모 프로젝트에서 명확하고 체계적인 개발 프로세스를 제공합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;브랜치 구조&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;master&lt;/b&gt;: 프로덕션 코드가 위치하는 브랜치로, 최종 릴리즈된 안정된 버전만 포함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;develop&lt;/b&gt;: 개발 중인 코드를 통합하는 브랜치. 모든 새로운 기능이 여기에서 시작&lt;/li&gt;
&lt;li&gt;&lt;b&gt;feature&lt;/b&gt;: 특정 기능을 개발하기 위한 임시 브랜치로, 작업이 완료되면 develop 브랜치로 병합&lt;/li&gt;
&lt;li&gt;&lt;b&gt;release&lt;/b&gt;: 릴리즈 준비를 위한 브랜치로, 테스트 및 최종 검증 작업이 수행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;hotfix&lt;/b&gt;: 긴급 수정이 필요한 경우 master 브랜치에서 파생되어 작업 후 다시 master와 develop에 병합&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;명확한 브랜치 구조를 통해 안정성과 품질 유지&lt;/li&gt;
&lt;li&gt;대규모 팀에서 각기 다른 작업을 분리하여 충돌 최소화&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브랜치 복잡도가 높아 관리가 어렵고 초보자에게는 부담될 수 있음&lt;/li&gt;
&lt;li&gt;빠른 배포를 요구하는 환경에서는 비효율적&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. GitHub Flow 개요&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;GitHub Flow&lt;/b&gt;는 간단하고 직관적인 브랜치 전략으로, Pull Request(PR)를 중심으로 협업합니다. 빠른 배포가 필요한 프로젝트에서 유용합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;브랜치 구조&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;master&lt;/b&gt;: 단일 브랜치로, 모든 코드가 배포 준비 상태를 유지&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Feature 브랜치&lt;/b&gt;: 단기적인 작업을 위한 브랜치로, 작업 완료 후 PR을 통해 master에 병합&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;워크플로우&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;작업을 시작할 때 master에서 Feature 브랜치를 생성&lt;/li&gt;
&lt;li&gt;기능 구현 및 테스트를 완료&lt;/li&gt;
&lt;li&gt;PR을 생성하여 코드 리뷰 요청&lt;/li&gt;
&lt;li&gt;리뷰가 완료되면 master에 병합&lt;/li&gt;
&lt;li&gt;자동 배포 또는 수동 배포 수행&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;간단한 구조로 사용이 용이하며 초보자도 쉽게 적용 가능&lt;/li&gt;
&lt;li&gt;Pull Request 중심의 협업으로 코드 리뷰와 CI/CD 통합이 쉬움&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;릴리즈 관리가 필요한 대규모 프로젝트에는 적합하지 않음&lt;/li&gt;
&lt;li&gt;장기적인 기능 개발에는 비효율적일 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. GitLab Flow 개요&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;GitLab Flow&lt;/b&gt;는 GitHub Flow의 단순함을 유지하면서, CI/CD 파이프라인과 연계하여 배포 프로세스를 체계적으로 관리하는 전략입니다. 환경별 브랜치를 추가하여 다양한 배포 환경을 지원합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;브랜치 구조&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;master&lt;/b&gt;: 항상 프로덕션 배포 준비 상태를 유지&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Feature 브랜치&lt;/b&gt;: 기능 개발용 브랜치&lt;/li&gt;
&lt;li&gt;&lt;b&gt;환경별 브랜치&lt;/b&gt;: &lt;code&gt;staging&lt;/code&gt;, &lt;code&gt;production&lt;/code&gt;과 같은 환경별 브랜치로 릴리즈 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;워크플로우&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Feature 브랜치에서 작업 시작&lt;/li&gt;
&lt;li&gt;작업 완료 후 master에 병합&lt;/li&gt;
&lt;li&gt;CI/CD 파이프라인이 자동으로 테스트와 빌드를 수행&lt;/li&gt;
&lt;li&gt;staging 브랜치를 통해 테스트 환경에 배포&lt;/li&gt;
&lt;li&gt;최종 검증 후 production 브랜치로 배포&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CI/CD와 자연스럽게 통합되며, 배포 프로세스가 명확&lt;/li&gt;
&lt;li&gt;환경별 브랜치로 릴리즈와 배포를 체계적으로 관리 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;환경별 브랜치 관리로 인해 복잡도가 증가할 수 있음&lt;/li&gt;
&lt;li&gt;소규모 팀이나 간단한 프로젝트에는 오히려 부담이 될 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 브랜치 전략 비교&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;전략&lt;/th&gt;
&lt;th&gt;브랜치 구조&lt;/th&gt;
&lt;th&gt;주요 특징&lt;/th&gt;
&lt;th&gt;적합한 프로젝트&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Git Flow&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;master&lt;/code&gt;, &lt;code&gt;develop&lt;/code&gt;, &lt;code&gt;feature&lt;/code&gt; 등&lt;/td&gt;
&lt;td&gt;안정성 중시, 복잡한 구조&lt;/td&gt;
&lt;td&gt;대규모 프로젝트, 안정성 중요 환경&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;GitHub Flow&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;master&lt;/code&gt;와 Feature 브랜치만 사용&lt;/td&gt;
&lt;td&gt;간단한 구조, PR 중심 협업&lt;/td&gt;
&lt;td&gt;소규모 프로젝트, 빠른 배포 환경&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;GitLab Flow&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;master&lt;/code&gt;, 환경별 브랜치(&lt;code&gt;staging&lt;/code&gt; 등)&lt;/td&gt;
&lt;td&gt;배포와 CI/CD 중심&lt;/td&gt;
&lt;td&gt;중규모 프로젝트, 배포 프로세스 중시&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 프로젝트 환경에 따른 선택 가이드&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Git Flow를 선택하세요:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;릴리즈 주기가 길고, 안정성이 중요한 대규모 프로젝트&lt;/li&gt;
&lt;li&gt;여러 팀이 동시에 작업하며 기능별 분리가 필요한 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GitHub Flow를 선택하세요:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빠른 배포가 중요한 소규모 프로젝트&lt;/li&gt;
&lt;li&gt;간단한 브랜치 구조와 PR 기반 협업을 선호하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GitLab Flow를 선택하세요:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CI/CD 파이프라인과 연계한 배포가 중요한 프로젝트&lt;/li&gt;
&lt;li&gt;환경별 브랜치 관리로 릴리즈를 체계적으로 관리하려는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 최종 결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 가지 브랜치 전략은 각각의 장단점이 뚜렷하며, 프로젝트의 규모, 팀 구성, 릴리즈 주기 등 다양한 요소에 따라 적합성이 달라집니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Git Flow&lt;/b&gt;: 대규모 프로젝트에서 안정성을 중시할 때&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GitHub Flow&lt;/b&gt;: 소규모 팀에서 빠른 배포와 간단한 협업을 원할 때&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GitLab Flow&lt;/b&gt;: CI/CD와 배포 프로세스를 중시하는 환경에서&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러분의 프로젝트에 적합한 브랜치 전략을 선택해 협업과 릴리즈 관리의 효율성을 높여 보세요. 이번 포스팅이 선택에 도움이 되길 바랍니다!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://nvie.com/posts/a-successful-git-branching-model/&quot;&gt;Git Flow 공식 가이드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/get-started/quickstart/github-flow&quot;&gt;GitHub Flow 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.gitlab.com/ee/topics/gitlab_flow.html&quot;&gt;GitLab Flow 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다!&lt;/p&gt;</description>
      <category>Git</category>
      <category>CI/CD</category>
      <category>GIT</category>
      <category>Git Flow</category>
      <category>git 워크플로우</category>
      <category>github flow</category>
      <category>gitlab flow</category>
      <category>개발 협업</category>
      <category>버전 관리</category>
      <category>브랜치 전략</category>
      <category>소프트웨어 개발 전략</category>
      <author>422haha</author>
      <guid isPermaLink="true">https://dev-miyeon.tistory.com/7</guid>
      <comments>https://dev-miyeon.tistory.com/7#entry7comment</comments>
      <pubDate>Fri, 10 Jan 2025 15:01:35 +0900</pubDate>
    </item>
    <item>
      <title>Git 커밋 컨벤션 가이드: 협업을 위한 베스트 프랙티스</title>
      <link>https://dev-miyeon.tistory.com/6</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요! 이번 포스팅에서는 &lt;b&gt;Git 커밋 컨벤션&lt;/b&gt;에 대해 알아보고, 협업 프로젝트에서 일관된 커밋 메시지를 작성하기 위한 베스트 프랙티스를 공유합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깔끔하고 일관된 커밋 메시지는 협업 과정에서 팀원 간의 이해도를 높이고, 프로젝트 유지보수를 쉽게 만들어줍니다. 이 글을 통해 커밋 메시지 작성 규칙과 실무에서 바로 적용 가능한 팁을 얻어가시길 바랍니다!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#1-git-%EC%BB%A4%EB%B0%8B-%EC%BB%A8%EB%B2%A4%EC%85%98%EC%9D%B4%EB%9E%80&quot;&gt;Git 커밋 컨벤션이란?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#2-%EC%BB%A4%EB%B0%8B-%EB%A9%94%EC%8B%9C%EC%A7%80%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EA%B5%AC%EC%A1%B0&quot;&gt;커밋 메시지의 기본 구조&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#3-%EB%8C%80%ED%91%9C%EC%A0%81%EC%9D%B8-%EC%BB%A4%EB%B0%8B-%EC%BB%A8%EB%B2%A4%EC%85%98-%EC%8A%A4%ED%83%80%EC%9D%BC&quot;&gt;대표적인 커밋 컨벤션 스타일&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#4-%ED%98%91%EC%97%85%EC%9D%84-%EC%9C%84%ED%95%9C-%EC%BB%A4%EB%B0%8B-%EC%9E%91%EC%84%B1-%EB%B2%A0%EC%8A%A4%ED%8A%B8-%ED%94%84%EB%9E%99%ED%8B%B0%EC%8A%A4&quot;&gt;협업을 위한 커밋 작성 베스트 프랙티스&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#5-%EC%BB%A4%EB%B0%8B-%EB%A9%94%EC%8B%9C%EC%A7%80-%EC%9E%91%EC%84%B1-%EB%8F%84%EA%B5%AC%EC%99%80-%EC%9E%90%EB%8F%99%ED%99%94&quot;&gt;커밋 메시지 작성 도구와 자동화&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Git 커밋 컨벤션이란?&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;125&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dhJVjS/btsLCtwgvJm/FgQzLZk0RX675XGJo3QeN1/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dhJVjS/btsLCtwgvJm/FgQzLZk0RX675XGJo3QeN1/tfile.svg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dhJVjS/btsLCtwgvJm/FgQzLZk0RX675XGJo3QeN1/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdhJVjS%2FbtsLCtwgvJm%2FFgQzLZk0RX675XGJo3QeN1%2Ftfile.svg&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;300&quot; height=&quot;125&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;125&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Git 커밋 컨벤션&lt;/b&gt;은 협업 프로젝트에서 일관된 커밋 메시지를 작성하기 위한 규칙입니다. 이를 통해 다음과 같은 장점을 얻을 수 있습니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드 변경의 히스토리를 명확하게 기록&lt;/li&gt;
&lt;li&gt;코드 리뷰 과정에서 의사소통 원활화&lt;/li&gt;
&lt;li&gt;자동화 도구(릴리즈 로그 생성, 테스트 실행 등)와의 통합 용이성&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 커밋 메시지의 기본 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 커밋 메시지는 다음과 같은 구조를 따릅니다:&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;타입&amp;gt;(&amp;lt;스코프&amp;gt;): &amp;lt;짧은 설명&amp;gt;

&amp;lt;본문&amp;gt;

&amp;lt;푸터&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 제목 (Title)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;50자 이내&lt;/b&gt;로 작성&lt;/li&gt;
&lt;li&gt;현재형 동사를 사용 (e.g., &quot;Add&quot;, &quot;Fix&quot;, &quot;Update&quot;)&lt;/li&gt;
&lt;li&gt;첫 글자는 대문자, 마침표는 사용하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 본문 (Body)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;변경 사항의 상세 설명을 작성&lt;/li&gt;
&lt;li&gt;&quot;무엇을&quot;, &quot;왜&quot; 변경했는지 중심으로 작성&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3 푸터 (Footer)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;버그 트래커 ID, Breaking Changes, 참조 정보를 포함&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 대표적인 커밋 컨벤션 스타일&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 Conventional Commits&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;널리 사용되는 컨벤션으로, 제목에 &lt;code&gt;타입&lt;/code&gt;과 &lt;code&gt;스코프&lt;/code&gt;를 명시합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;http&quot;&gt;&lt;code&gt;feat(auth): Add JWT authentication support

This update implements JWT authentication for secure API access. Added token validation middleware.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;타입 목록:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;feat&lt;/b&gt;: 새로운 기능 추가&lt;/li&gt;
&lt;li&gt;&lt;b&gt;fix&lt;/b&gt;: 버그 수정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;docs&lt;/b&gt;: 문서 수정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;style&lt;/b&gt;: 코드 스타일 변경 (동작 변경 없음)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;refactor&lt;/b&gt;: 코드 리팩토링&lt;/li&gt;
&lt;li&gt;&lt;b&gt;test&lt;/b&gt;: 테스트 추가 또는 수정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;chore&lt;/b&gt;: 기타 변경 사항 (빌드, 설정 파일 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 Gitmoji&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이모지를 활용해 커밋 메시지의 목적을 시각적으로 표현합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;  feat: Add user profile feature
 ️ fix: Resolve login page bug&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3 Custom 스타일&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀에서 별도로 정의한 규칙을 사용하기도 합니다. 프로젝트에 맞는 유연한 스타일을 채택하세요.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 협업을 위한 커밋 작성 베스트 프랙티스&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;의미 있는 단위로 커밋하기&lt;/b&gt;: 한 커밋에는 하나의 변경 사항만 포함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;현재형 동사 사용&lt;/b&gt;: &quot;Added&quot; 대신 &quot;Add&quot;와 같은 현재형 사용.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;짧고 명확하게 작성&lt;/b&gt;: 제목은 50자, 본문은 필요 시 72자 단위로 줄바꿈.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;팀 컨벤션 준수&lt;/b&gt;: 팀원 간 합의된 스타일 유지.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자동화 도구 활용&lt;/b&gt;: Linter나 pre-commit 훅으로 일관성 강제.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 커밋 메시지 작성 도구와 자동화&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1 Commitizen&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Conventional Commits 스타일로 커밋을 작성하도록 돕는 CLI 도구.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설치 및 사용:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;q&quot;&gt;&lt;code&gt;npm install -g commitizen
commitizen init cz-conventional-changelog --save-dev --save-exact&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.2 Linting 도구&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Husky를 사용해 pre-commit 훅으로 커밋 메시지 규칙 검사.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설치 및 설정:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;npm install husky --save-dev
npx husky add .husky/commit-msg 'npx commitlint --edit &quot;$1&quot;'&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;최종 결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일관된 Git 커밋 메시지 작성은 협업의 효율성을 높이고 프로젝트 관리에 큰 도움을 줍니다. 위에서 소개한 규칙과 도구를 활용하여 팀 내에서 통일된 컨벤션을 적용해 보세요. 더 나아가, 커밋 히스토리를 통해 과거의 변경 사항을 쉽게 이해하고 관리할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러분의 프로젝트에서 효과적인 Git 사용이 이루어지길 바랍니다! 감사합니다.&lt;/p&gt;</description>
      <category>Git</category>
      <category>GIT</category>
      <category>git 사용법</category>
      <category>git 커밋 규칙</category>
      <category>git 협업</category>
      <category>개발 협업</category>
      <category>개발자 가이드</category>
      <category>버전 관리</category>
      <category>커밋 메시지</category>
      <category>커밋 컨벤션</category>
      <category>협업 팁</category>
      <author>422haha</author>
      <guid isPermaLink="true">https://dev-miyeon.tistory.com/6</guid>
      <comments>https://dev-miyeon.tistory.com/6#entry6comment</comments>
      <pubDate>Fri, 3 Jan 2025 17:28:31 +0900</pubDate>
    </item>
    <item>
      <title>Django vs Spring 비교: 프로젝트 환경에 맞는 백엔드 프레임워크 선택 가이드</title>
      <link>https://dev-miyeon.tistory.com/5</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요! 이번 포스팅에서는 &lt;b&gt;Django&lt;/b&gt;와 &lt;b&gt;Spring&lt;/b&gt;의 특징을 비교하고, 각 프레임워크가 어떤 프로젝트 환경에 더 적합한지 정리해 보겠습니다.&lt;br /&gt;백엔드 프레임워크 선택은 프로젝트의 &lt;b&gt;규모&lt;/b&gt;, &lt;b&gt;팀 역량&lt;/b&gt;, &lt;b&gt;개발 언어 선호도&lt;/b&gt; 등에 따라 크게 달라질 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Django&lt;/b&gt;: 파이썬(Python) 기반으로 간결한 문법과 빠른 프로토타이핑에 강점&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Spring&lt;/b&gt;: 자바(Java) 기반으로 엔터프라이즈급 애플리케이션에서 검증된 안정성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅을 통해 어떤 프레임워크가 여러분의 프로젝트에 가장 적합한지 판단하는 데 도움이 되길 바랍니다!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#1-django%EC%99%80-spring-%EA%B0%9C%EC%9A%94&quot;&gt;Django와 Spring 개요&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#2-%EA%B0%9C%EB%B0%9C-%EC%96%B8%EC%96%B4-%EB%B0%8F-%EC%A3%BC%EC%9A%94-%ED%8A%B9%EC%A7%95-%EB%B9%84%EA%B5%90&quot;&gt;개발 언어 및 주요 특징 비교&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#3-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98%EC%99%80-mvc-%ED%8C%A8%ED%84%B4&quot;&gt;아키텍처와 MVC 패턴&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#4-%EC%83%9D%ED%83%9C%EA%B3%84%EC%99%80-%EC%BB%A4%EB%AE%A4%EB%8B%88%ED%8B%B0-%EC%A7%80%EC%9B%90&quot;&gt;생태계와 커뮤니티 지원&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#5-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EB%B0%8F-orm-%EC%A7%80%EC%9B%90&quot;&gt;데이터베이스 및 ORM 지원&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#6-%ED%99%95%EC%9E%A5%EC%84%B1-%EB%B0%8F-%EB%B0%B0%ED%8F%AC-%ED%99%98%EA%B2%BD&quot;&gt;확장성 및 배포 환경&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#7-%EB%B3%B4%EC%95%88-%EB%B0%8F-%EC%9D%B8%EC%A6%9D&quot;&gt;보안 및 인증&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#8-%ED%95%99%EC%8A%B5-%EA%B3%A1%EC%84%A0%EA%B3%BC-%ED%8C%80-%EC%97%AD%EB%9F%89-%EA%B3%A0%EB%A0%A4&quot;&gt;학습 곡선과 팀 역량 고려&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#9-%EC%B5%9C%EC%A2%85-%EA%B2%B0%EB%A1%A0&quot;&gt;최종 결론&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Django와 Spring 개요&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;543&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chIXfg/btsLzDSKB2x/GGfz6fN0EKXNaXxGsbwKAk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chIXfg/btsLzDSKB2x/GGfz6fN0EKXNaXxGsbwKAk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chIXfg/btsLzDSKB2x/GGfz6fN0EKXNaXxGsbwKAk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchIXfg%2FbtsLzDSKB2x%2FGGfz6fN0EKXNaXxGsbwKAk%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;1214&quot; height=&quot;543&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;543&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.1 Django&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;파이썬(Python)&lt;/b&gt; 기반으로 빠른 개발과 유지보수가 용이합니다.&lt;/li&gt;
&lt;li&gt;&amp;lsquo;배터리가 포함된(Batteries Included)&amp;rsquo; 철학으로, 웹 개발에 필요한 기능을 기본 제공하여 &lt;b&gt;MVP&lt;/b&gt;나 &lt;b&gt;프로토타입&lt;/b&gt; 제작에 유리합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;소규모부터 중규모&lt;/b&gt; 프로젝트까지, 빠른 프로토타이핑을 선호하는 팀에 적합합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.2 Spring&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;자바(Java)&lt;/b&gt; 기반으로, &lt;b&gt;엔터프라이즈급 애플리케이션&lt;/b&gt; 개발에 최적화되어 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스프링 부트(Spring Boot)&lt;/b&gt;, &lt;b&gt;스프링 시큐리티(Spring Security)&lt;/b&gt; 등 다양한 모듈을 통해 복잡한 기능을 세분화해 구축할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대규모&lt;/b&gt; 프로젝트와 여러 서버 인프라 환경에서 검증된 &lt;b&gt;안정성&lt;/b&gt;과 &lt;b&gt;확장성&lt;/b&gt;을 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 개발 언어 및 주요 특징 비교&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 Django (Python)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문법이 &lt;b&gt;간결&lt;/b&gt;하고 직관적이어서, 파이썬 경험이 없는 초보자도 비교적 빠르게 학습할 수 있습니다.&lt;/li&gt;
&lt;li&gt;파이썬 생태계를 통해 &lt;b&gt;머신 러닝&lt;/b&gt;, &lt;b&gt;데이터 분석&lt;/b&gt;, &lt;b&gt;스크립트 자동화&lt;/b&gt; 등 다양한 분야와 연계가 용이합니다.&lt;/li&gt;
&lt;li&gt;내장 &lt;b&gt;관리자(Administration) 페이지&lt;/b&gt; 등을 제공해, 관리자 기능을 구현하기가 용이합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 Spring (Java)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정적 타입&lt;/b&gt; 언어로, 대규모 코드베이스에서 &lt;b&gt;유지보수&lt;/b&gt;에 안정적입니다.&lt;/li&gt;
&lt;li&gt;풍부한 오픈소스 라이브러리(예: Maven, Gradle)와의 호환성이 뛰어나며,&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Spring Boot&lt;/b&gt;를 사용하면 기본 설정이 단순화되어 초반 세팅이 쉬워지지만, 여전히 &lt;b&gt;엔터프라이즈급&lt;/b&gt; 확장성을 유지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 아키텍처와 MVC 패턴&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 Django&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;MTV(Model-Template-View)&lt;/b&gt; 패턴을 기반으로, 전통적인 MVC와 유사한 구조이지만 템플릿과 뷰가 조금 다른 개념으로 구분됩니다.&lt;/li&gt;
&lt;li&gt;URL 패턴, 뷰, 모델, 템플릿 파일 구조가 명확해, 프로젝트 규모가 커져도 비교적 직관적으로 관리할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 Spring&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;MVC(Model-View-Controller)&lt;/b&gt; 패턴을 기반으로,&lt;/li&gt;
&lt;li&gt;&lt;b&gt;의존성 주입(Dependency Injection)&lt;/b&gt;, &lt;b&gt;제어의 역전(Inversion of Control)&lt;/b&gt; 등 스프링만의 특징을 통해 &lt;b&gt;유연한 계층 아키텍처&lt;/b&gt;를 구성할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;마이크로서비스 아키텍처(MSA)&lt;/b&gt;로 확장하기도 용이해, 대규모 엔터프라이즈 환경에서 널리 채택됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 생태계와 커뮤니티 지원&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1 Django&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;파이썬 커뮤니티&lt;/b&gt;와 패키지 인덱스(&lt;b&gt;PyPI&lt;/b&gt;)의 수많은 패키지를 활용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;Django 자체 문서와 오픈소스 튜토리얼, 예제 코드가 풍부해, 학습과 문제 해결이 비교적 수월합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2 Spring&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;자바 생태계&lt;/b&gt;의 대표적 프레임워크로, 엔터프라이즈급 사례가 풍부합니다.&lt;/li&gt;
&lt;li&gt;Stack Overflow, GitHub 등에서 &lt;b&gt;Spring&lt;/b&gt; 관련 자료가 방대하게 축적되어 있으며,&lt;/li&gt;
&lt;li&gt;세계적으로 가장 큰 자바 기반 커뮤니티 가운데 하나로 활발히 운영됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 데이터베이스 및 ORM 지원&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1 Django&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Django ORM&lt;/b&gt;을 통해 데이터베이스 연동을 간단하게 처리하며,&lt;/li&gt;
&lt;li&gt;MySQL, PostgreSQL, SQLite 등 대부분의 &lt;b&gt;관계형 DB&lt;/b&gt;에 쉽게 연결할 수 있습니다.&lt;/li&gt;
&lt;li&gt;기본 ORM이 프레임워크에 &lt;b&gt;내장&lt;/b&gt;되어 있어, 추가 설정 없이도 &lt;b&gt;CRUD&lt;/b&gt; 작업을 빠르게 구현할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.2 Spring&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;JPA(Java Persistence API)&lt;/b&gt;를 비롯해 &lt;b&gt;Hibernate&lt;/b&gt;, &lt;b&gt;MyBatis&lt;/b&gt; 등 다양한 ORM/매퍼를 선택해서 사용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;프로젝트 특성(고성능, 복잡한 쿼리, 기업 규격 등)에 맞춰 &lt;b&gt;ORM&lt;/b&gt; 또는 &lt;b&gt;SQL 매퍼&lt;/b&gt;를 자유롭게 구성할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 확장성 및 배포 환경&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.1 Django&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Gunicorn&lt;/b&gt;, &lt;b&gt;uWSGI&lt;/b&gt; 등을 활용해 간단히 웹 서버와 연동할 수 있으며,&lt;/li&gt;
&lt;li&gt;Docker, Kubernetes 등을 통해 &lt;b&gt;클라우드 환경&lt;/b&gt;으로 배포하기도 쉽습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서버리스(Serverless)&lt;/b&gt; 환경(예: AWS Lambda)에서도 파이썬 함수 형태로 활용 가능해 확장성이 높습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.2 Spring&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Jar&lt;/b&gt; 혹은 &lt;b&gt;War&lt;/b&gt; 패키지 형태로 배포 가능하며, &lt;b&gt;Spring Boot&lt;/b&gt;를 사용하면 실행 가능한 Jar로 쉽게 배포할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Kubernetes&lt;/b&gt;, &lt;b&gt;Spring Cloud&lt;/b&gt; 등과 연계해 마이크로서비스 아키텍처로 확장이 수월하며,&lt;/li&gt;
&lt;li&gt;엔터프라이즈 환경 표준으로 자리 잡아 운영 노하우가 풍부합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 보안 및 인증&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.1 Django&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CSRF 토큰&lt;/b&gt;, &lt;b&gt;XSS 방어&lt;/b&gt; 등 기본적인 웹 보안 요소를 프레임워크 차원에서 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Django Rest Framework(DRF)&lt;/b&gt;와 연동하면 &lt;b&gt;OAuth&lt;/b&gt;나 &lt;b&gt;JWT&lt;/b&gt; 같은 인증 방식도 쉽게 구현 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.2 Spring&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Spring Security&lt;/b&gt; 모듈을 통해 세밀한 보안 정책을 구성할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OAuth2&lt;/b&gt;, &lt;b&gt;JWT&lt;/b&gt;, &lt;b&gt;LDAP&lt;/b&gt;, &lt;b&gt;SAML&lt;/b&gt; 등 다양한 인증/인가 방식을 지원하며,&lt;/li&gt;
&lt;li&gt;엔터프라이즈급 &lt;b&gt;SSO(Single Sign-On)&lt;/b&gt; 환경 구축에도 강력한 기능을 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 학습 곡선과 팀 역량 고려&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Django&lt;/b&gt;: 파이썬을 이미 알고 있거나, 간단한 웹 프로젝트를 &lt;b&gt;빠르게 시작&lt;/b&gt;하고자 하는 팀에 유리합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Spring&lt;/b&gt;: 자바 언어에 익숙하거나, &lt;b&gt;대규모 엔터프라이즈&lt;/b&gt; 수준의 프로젝트 경험을 보유한 팀에 적합합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 최종 결론&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Django&lt;/b&gt;: 빠른 &lt;b&gt;프로토타이핑&lt;/b&gt;, 간결한 문법, &lt;b&gt;파이썬&lt;/b&gt; 생태계를 활용하고 싶은 &lt;b&gt;소규모~중규모&lt;/b&gt; 웹 프로젝트에 권장됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Spring&lt;/b&gt;: &lt;b&gt;자바&lt;/b&gt; 기반의 안정성, &lt;b&gt;대규모 프로젝트&lt;/b&gt; 및 기업 환경에서 쌓인 운영 노하우가 필요한 &lt;b&gt;엔터프라이즈&lt;/b&gt;급 프로젝트에 적합합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅이 Django와 Spring 중 적절한 선택을 내리는 데 도움이 되셨길 바랍니다.&lt;br /&gt;팀 역량과 프로젝트 규모, 그리고 배포 환경 등을 고려해 &lt;b&gt;최적의 백엔드 프레임워크&lt;/b&gt;를 선택하시기 바랍니다!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.djangoproject.com/&quot;&gt;Django 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spring.io/projects/spring-boot&quot;&gt;Spring 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pypi.org/&quot;&gt;Python 패키지 인덱스(PyPI)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://maven.apache.org/&quot;&gt;Maven, Gradle 공식 문서&lt;/a&gt; | &lt;a href=&quot;https://gradle.org/&quot;&gt;https://gradle.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;주의 사항&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프레임워크 선택 시 프로젝트 요구 사항, &lt;b&gt;팀 전문성&lt;/b&gt;, &lt;b&gt;확장성&lt;/b&gt; 등을 신중히 고려하시기 바랍니다.&lt;/li&gt;
&lt;li&gt;Django와 Spring 모두 지속적으로 버전이 업데이트되고 있으므로, &lt;b&gt;라이브러리 호환성&lt;/b&gt;과 &lt;b&gt;릴리즈 노트&lt;/b&gt;를 꾸준히 확인하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;b&gt;Django&lt;/b&gt;와 &lt;b&gt;Spring&lt;/b&gt;의 특성을 잘 이해하고, 여러분의 프로젝트 환경에 맞춰 최고의 백엔드 프레임워크를 선택해 보시길 바랍니다. 성공적인 개발을 응원합니다!&lt;/p&gt;</description>
      <category>Backend</category>
      <category>Django</category>
      <category>django vs spring</category>
      <category>ORM</category>
      <category>Spring</category>
      <category>개발언어비교</category>
      <category>백엔드프레임워크</category>
      <category>웹개발</category>
      <category>자바</category>
      <category>파이썬</category>
      <category>프레임워크비교</category>
      <author>422haha</author>
      <guid isPermaLink="true">https://dev-miyeon.tistory.com/5</guid>
      <comments>https://dev-miyeon.tistory.com/5#entry5comment</comments>
      <pubDate>Fri, 27 Dec 2024 14:12:05 +0900</pubDate>
    </item>
    <item>
      <title>유니티 vs 언리얼 엔진 비교: 프로젝트 환경에 맞는 게임 엔진 선택 가이드</title>
      <link>https://dev-miyeon.tistory.com/4</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요! 이번 포스팅에서는 &lt;b&gt;유니티(Unity)&lt;/b&gt;와 &lt;b&gt;언리얼 엔진(Unreal Engine)&lt;/b&gt;의 특징을 비교하고, 각 엔진이 어떤 프로젝트 환경에 더 적합한지 정리해 보겠습니다. 게임 엔진 선택은 프로젝트의 &lt;b&gt;규모, 목표 품질, 개발팀 역량&lt;/b&gt;에 따라 달라질 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;유니티(Unity)&lt;/b&gt;는 비교적 진입 장벽이 낮아 &lt;b&gt;소규모 팀&lt;/b&gt;과 &lt;b&gt;2D/모바일 게임&lt;/b&gt;에 적합합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;언리얼 엔진(Unreal Engine)&lt;/b&gt;은 고급 그래픽과 &lt;b&gt;대규모 AAA급 프로젝트&lt;/b&gt;에 강력한 성능을 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅을 통해 어떤 엔진이 여러분의 프로젝트에 가장 적합한지 판단하는 데 도움이 되길 바랍니다!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#1-%EC%9C%A0%EB%8B%88%ED%8B%B0%EC%99%80-%EC%96%B8%EB%A6%AC%EC%96%BC-%EC%97%94%EC%A7%84-%EA%B0%9C%EC%9A%94&quot;&gt;유니티와 언리얼 엔진 개요&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#2-%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8C%85-%EC%96%B8%EC%96%B4-%EB%B0%8F-%EB%B9%84%EC%A3%BC%EC%96%BC-%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8C%85-%EB%B9%84%EA%B5%90&quot;&gt;스크립팅 언어 및 비주얼 스크립팅 비교&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#3-2d-%EB%B0%8F-3d-%EC%A7%80%EC%9B%90-%EB%B2%94%EC%9C%84&quot;&gt;2D 및 3D 지원 범위&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#4-%EC%95%A0%EC%85%8B-%EB%A7%88%EC%BC%93%ED%94%8C%EB%A0%88%EC%9D%B4%EC%8A%A4-%EB%B9%84%EA%B5%90&quot;&gt;애셋 마켓플레이스 비교&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#5-%EC%9E%91%EC%97%85-%EC%86%8D%EB%8F%84-%EB%B0%8F-%EA%B2%B0%EA%B3%BC%EB%AC%BC-%ED%92%88%EC%A7%88&quot;&gt;작업 속도 및 결과물 품질&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#6-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B7%9C%EB%AA%A8-%EB%B0%8F-%ED%99%95%EC%9E%A5%EC%84%B1&quot;&gt;프로젝트 규모 및 확장성&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#7-%ED%95%9C%EA%B5%AD%EC%96%B4-%EC%A7%80%EC%9B%90-%EB%B0%8F-%EC%BB%A4%EB%AE%A4%EB%8B%88%ED%8B%B0&quot;&gt;한국어 지원 및 커뮤니티&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#8-%EB%B3%B4%EC%95%88-%EB%B0%8F-%EC%BD%94%EB%93%9C-%EC%A0%91%EA%B7%BC%EC%84%B1&quot;&gt;보안 및 코드 접근성&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#9-%EC%B5%9C%EC%A2%85-%EA%B2%B0%EB%A1%A0&quot;&gt;최종 결론&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 유니티와 언리얼 엔진 개요&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwElyR/btsLkJyZvpj/iy3IJqjDn3g53zNql5lZ21/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwElyR/btsLkJyZvpj/iy3IJqjDn3g53zNql5lZ21/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwElyR/btsLkJyZvpj/iy3IJqjDn3g53zNql5lZ21/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwElyR%2FbtsLkJyZvpj%2Fiy3IJqjDn3g53zNql5lZ21%2Fimg.webp&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;1920&quot; height=&quot;1080&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.1 &lt;b&gt;유니티(Unity)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;가볍고 빠른 작업&lt;/b&gt;이 장점인 게임 엔진입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;2D/3D&lt;/b&gt;, 특히 &lt;b&gt;모바일 게임&lt;/b&gt; 개발에 강점이 있습니다.&lt;/li&gt;
&lt;li&gt;소규모 팀이나 &lt;b&gt;1인 개발자&lt;/b&gt;에게 적합합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.2 &lt;b&gt;언리얼 엔진(Unreal Engine)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고품질 &lt;b&gt;3D 그래픽&lt;/b&gt;과 &lt;b&gt;AAA급 프로젝트&lt;/b&gt;에 특화된 엔진입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대규모 팀&lt;/b&gt;과 복잡한 프로젝트에 적합합니다.&lt;/li&gt;
&lt;li&gt;초반 학습 곡선이 가파르지만 &lt;b&gt;확장성&lt;/b&gt;과 &lt;b&gt;퍼포먼스&lt;/b&gt;가 뛰어납니다.&lt;/li&gt;
&lt;li&gt;게임뿐만 아니라 &lt;b&gt;가상 프로덕션&lt;/b&gt;, &lt;b&gt;건축 시뮬레이션&lt;/b&gt;, &lt;b&gt;영화 제작&lt;/b&gt; 분야에도 활용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 스크립팅 언어 및 비주얼 스크립팅 비교&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 &lt;b&gt;유니티(Unity)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;스크립팅 언어&lt;/b&gt;: &lt;b&gt;C#&lt;/b&gt; 기반으로 배우기 쉽고 접근성이 높습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비주얼 스크립팅&lt;/b&gt;: 기존 &lt;b&gt;Bolt&lt;/b&gt;를 기반으로 현재는 &lt;b&gt;Unity Visual Scripting&lt;/b&gt;으로 통합되었으며, 기능이 꾸준히 개선되고 있습니다.&lt;/li&gt;
&lt;li&gt;비프로그래머 직군도 &lt;b&gt;빠르게 접근 가능&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 &lt;b&gt;언리얼 엔진(Unreal Engine)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;스크립팅 언어&lt;/b&gt;: &lt;b&gt;C++&lt;/b&gt; 기반으로 고성능과 최적화를 제공하지만, 학습 곡선이 가파르고 초보자에게는 진입 장벽이 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비주얼 스크립팅&lt;/b&gt;: &lt;b&gt;블루프린트(Blueprint)&lt;/b&gt;를 통해 프로그래머 없이도 로직 구현이 가능합니다.&lt;/li&gt;
&lt;li&gt;신규 &lt;b&gt;Verse&lt;/b&gt; 언어 도입 예정으로 확장성이 강화될 예정입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 2D 및 3D 지원 범위&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 &lt;b&gt;유니티(Unity)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;2D 게임&lt;/b&gt; 개발에 특화된 기능을 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;3D 게임&lt;/b&gt;도 문제없이 개발 가능하지만 &lt;b&gt;고품질 그래픽&lt;/b&gt;을 구현하려면 추가 최적화가 필요할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 &lt;b&gt;언리얼 엔진(Unreal Engine)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;3D 그래픽&lt;/b&gt;에 특화되어 고사양 프로젝트에 강력한 성능을 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;2D 기능&lt;/b&gt;은 상대적으로 부족하지만 &lt;b&gt;Paper2D&lt;/b&gt;를 통해 2D 게임 개발이 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 애셋 마켓플레이스 비교&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1 &lt;b&gt;유니티 애셋 스토어&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;오랜 기간 축적된 방대한 애셋&lt;/b&gt;을 보유하고 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;저렴하고 다양한&lt;/b&gt; 애셋으로 &lt;b&gt;인디팀&lt;/b&gt;이나 &lt;b&gt;소규모 개발자&lt;/b&gt;에 적합합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2 &lt;b&gt;언리얼 엔진 Fab (구 마켓플레이스)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;고품질 무료 애셋&lt;/b&gt;과 &lt;b&gt;퀵셀 메가스캔&lt;/b&gt;이 통합되어 제공됩니다.&lt;/li&gt;
&lt;li&gt;언리얼 엔진 사용자는 &lt;b&gt;퀵셀 메가스캔&lt;/b&gt;을 무료로 활용할 수 있어 AAA급 프로젝트에 유리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 작업 속도 및 결과물 품질&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;b&gt;프로젝트 규모&lt;/b&gt;&lt;/th&gt;
&lt;th&gt;&lt;b&gt;유니티(Unity)&lt;/b&gt;&lt;/th&gt;
&lt;th&gt;&lt;b&gt;언리얼 엔진(Unreal Engine)&lt;/b&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;소규모/2D&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;빠른 개발 및 경량화가 장점&lt;/td&gt;
&lt;td&gt;다소 과도한 기능 제공&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;중간 규모&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;빠른 프로토타이핑 가능&lt;/td&gt;
&lt;td&gt;고퀄리티 그래픽 구현 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;대규모/3D&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;추가 최적화 필요&lt;/td&gt;
&lt;td&gt;고급 기능과 성능 제공, AAA 프로젝트에 최적화&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 프로젝트 규모 및 확장성&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;유니티(Unity)&lt;/b&gt;: 가볍고 &lt;b&gt;단순한 구조&lt;/b&gt;로 소규모 프로젝트에 유리하지만, 프로젝트가 커질수록 관리 부담이 커질 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;언리얼 엔진(Unreal Engine)&lt;/b&gt;: &lt;b&gt;대규모 프로젝트&lt;/b&gt;와 복잡한 그래픽 작업에 최적화되어 있으며, 소스 코드 접근성을 통해 확장성과 커스터마이징이 뛰어납니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 한국어 지원 및 커뮤니티&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;유니티(Unity)&lt;/b&gt;: 한국어 문서와 다양한 &lt;b&gt;튜토리얼&lt;/b&gt;을 제공하며 커뮤니티가 활성화되어 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;언리얼 엔진(Unreal Engine)&lt;/b&gt;: &lt;b&gt;한국어 문서&lt;/b&gt;가 있지만 일부 심화 내용은 &lt;b&gt;영어 문서&lt;/b&gt;를 참고해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 보안 및 코드 접근성&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;유니티(Unity)&lt;/b&gt;: &lt;b&gt;IL2CPP&lt;/b&gt;를 통해 보안을 강화할 수 있지만, 완전히 안전하지는 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;언리얼 엔진(Unreal Engine)&lt;/b&gt;: &lt;b&gt;C++ 기반&lt;/b&gt;으로 보안이 강력하며, 엔진 소스 코드 접근이 가능해 커스터마이징에 유리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 최종 결론&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;유니티(Unity)&lt;/b&gt;: &lt;b&gt;소규모 프로젝트&lt;/b&gt;, &lt;b&gt;2D 게임&lt;/b&gt;, &lt;b&gt;빠른 프로토타이핑&lt;/b&gt;에 유리합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;언리얼 엔진(Unreal Engine)&lt;/b&gt;: &lt;b&gt;대규모 프로젝트&lt;/b&gt;, &lt;b&gt;AAA급 게임&lt;/b&gt;, &lt;b&gt;고품질 그래픽&lt;/b&gt;에 강력한 성능을 제공하며, &lt;b&gt;비게임 분야&lt;/b&gt;에서도 활용됩니다.&lt;/li&gt;
&lt;/ul&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;b&gt;유니티(Unity)&lt;/b&gt;와 &lt;b&gt;언리얼 엔진(Unreal Engine)&lt;/b&gt; 중 적절한 선택을 내리는 데 도움이 되셨길 바랍니다. 프로젝트 환경과 목표에 맞는 엔진을 선택하여 성공적인 게임 개발을 시작해 보세요!  &lt;/p&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;b&gt;참고 자료&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://unity.com&quot;&gt;Unity 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.unrealengine.com&quot;&gt;Unreal Engine 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://quixel.com/megascans&quot;&gt;퀵셀 메가스캔&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;b&gt;주의 사항&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔진 선택 시 프로젝트의 요구 사항과 팀의 역량을 충분히 고려하시기 바랍니다.&lt;/li&gt;
&lt;li&gt;최신 엔진 업데이트와 커뮤니티 동향을 지속적으로 확인하는 것이 중요합니다.&lt;/li&gt;
&lt;/ul&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;이제 유니티(Unity)와 언리얼 엔진(Unreal Engine)의 특성을 잘 이해하고, 여러분의 프로젝트에 가장 적합한 엔진을 선택하여 성공적인 게임 개발을 진행해 보세요!&lt;/p&gt;</description>
      <category>Game Tech</category>
      <category>2d 게임 개발</category>
      <category>3d 게임 개발</category>
      <category>Unity</category>
      <category>unity vs unreal</category>
      <category>Unreal Engine</category>
      <category>게임 개발 입문</category>
      <category>게임 엔진</category>
      <category>언리얼 엔진</category>
      <category>유니티</category>
      <category>인디 게임 개발</category>
      <author>422haha</author>
      <guid isPermaLink="true">https://dev-miyeon.tistory.com/4</guid>
      <comments>https://dev-miyeon.tistory.com/4#entry4comment</comments>
      <pubDate>Tue, 17 Dec 2024 13:15:54 +0900</pubDate>
    </item>
    <item>
      <title>GitLab에서 GitHub로 미러링 시 민감 정보 안전하게 제거하기</title>
      <link>https://dev-miyeon.tistory.com/3</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요! 이번 포스팅에서는 &lt;b&gt;GitLab에서 GitHub로 리포지토리를 미러링&lt;/b&gt;하면서 발생할 수 있는 &lt;b&gt;민감 정보 제거&lt;/b&gt; 방법을 안내드립니다. 프로젝트를 이전하거나 협업 환경을 변경할 때, Git 히스토리에서 민감한 정보가 유출되지 않도록 처리하는 방법을 단계별로 살펴보겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#1-github%EC%97%90-private-%EB%A6%AC%ED%8F%AC%EC%A7%80%ED%86%A0%EB%A6%AC-%EC%83%9D%EC%84%B1&quot;&gt;GitHub에 Private 리포지토리 생성&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#2-gitlab-%EB%A6%AC%ED%8F%AC%EC%A7%80%ED%86%A0%EB%A6%AC-%EB%AF%B8%EB%9F%AC%EB%A7%81&quot;&gt;GitLab 리포지토리 미러링&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#3-%EB%AF%B8%EB%9F%AC%EB%A7%81%EB%90%9C-%EB%A6%AC%ED%8F%AC%EC%A7%80%ED%86%A0%EB%A6%AC-%ED%81%B4%EB%A1%A0&quot;&gt;미러링된 리포지토리 클론&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#4-gitignore-%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8-%EB%B0%8F-%EB%AF%BC%EA%B0%90-%ED%8C%8C%EC%9D%BC-%EC%A0%9C%EA%B1%B0&quot;&gt;&lt;code&gt;.gitignore&lt;/code&gt; 업데이트 및 민감 파일 제거&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#5-bfg-repo-cleaner%EB%A1%9C-%EB%AF%BC%EA%B0%90-%ED%8C%8C%EC%9D%BC-%EA%B8%B0%EB%A1%9D-%EC%A0%9C%EA%B1%B0&quot;&gt;BFG Repo-Cleaner로 민감 파일 기록 제거&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#6-git-%EC%A0%80%EC%9E%A5%EC%86%8C-%EC%A0%95%EB%A6%AC&quot;&gt;Git 저장소 정리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#7-%EB%B3%80%EA%B2%BD%EC%82%AC%ED%95%AD-%EA%B0%95%EC%A0%9C-%ED%91%B8%EC%8B%9C&quot;&gt;변경사항 강제 푸시&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#8-git-%EC%B5%9C%EC%A2%85-%EC%A0%95%EB%A6%AC&quot;&gt;Git 최종 정리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#9-%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C-%EB%B0%8F-%EA%B2%B0%EB%A1%A0&quot;&gt;참고 자료 및 결론&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. GitHub에 Private 리포지토리 생성&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;에 접속하여 로그인합니다.&lt;/li&gt;
&lt;li&gt;오른쪽 상단 &lt;b&gt;+&lt;/b&gt; 아이콘 클릭 &amp;rarr; &lt;b&gt;New Repository&lt;/b&gt; 선택.&lt;/li&gt;
&lt;li&gt;리포지토리 설정:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Repository name&lt;/b&gt;: 원하는 이름 입력. 예: &lt;code&gt;YOGANAVI-temp&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Privacy&lt;/b&gt;: &lt;b&gt;Private&lt;/b&gt; 선택.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Initialize this repository with a README&lt;/b&gt;: 초기화 없이 생성.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Create repository&lt;/b&gt; 클릭.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. GitLab 리포지토리 미러링&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GitLab 리포지토리를 GitHub로 미러링합니다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;git clone --mirror https://lab.ssafy.com/s11-webmobile4-sub2/S11P12D210.git
cd S11P12D210.git/
git push --mirror https://github.com/422haha/YOGANAVI-temp.git&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 미러링된 리포지토리 클론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GitHub로 미러링된 리포지토리를 로컬에 클론합니다.&lt;/p&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;git clone https://github.com/422haha/YOGANAVI-temp.git&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. &lt;code&gt;.gitignore&lt;/code&gt; 업데이트 및 민감 파일 제거&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;.gitignore&lt;/code&gt;를 업데이트하고 민감 파일을 제거합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;브랜치 체크아웃&lt;/b&gt;:&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git checkout dev-backend&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;.gitignore&lt;/code&gt; 업데이트&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래 내용을 추가:&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/.gradle /.idea /out /build *.iml *.ipr *.iws local.properties&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;파일 제거&lt;/b&gt;:&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git add . git commit -m &quot;Update .gitignore&quot; git push origin dev-backend&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. BFG Repo-Cleaner로 민감 파일 기록 제거&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://rtyley.github.io/bfg-repo-cleaner/&quot;&gt;BFG Repo-Cleaner&lt;/a&gt;를 사용하여 Git 기록에서 민감한 파일을 완전히 제거합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;BFG 다운로드 및 이동&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://rtyley.github.io/bfg-repo-cleaner/&quot;&gt;여기&lt;/a&gt;에서 &lt;b&gt;bfg-1.14.0.jar&lt;/b&gt; 파일을 다운로드합니다.&lt;/li&gt;
&lt;li&gt;프로젝트 루트 디렉토리로 파일을 이동합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;민감 파일 제거 명령어 실행&lt;/b&gt;:&lt;img src=&quot;https://blog.kakaocdn.net/dn/oVfOg/btsKQhvEPAU/Wu7FJh7eoSL53zPNPKNQT1/img.webp&quot; alt=&quot;&quot; /&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;java -jar bfg-1.14.0.jar --delete-files application.properties java -jar bfg-1.14.0.jar --delete-files local.properties&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. Git 저장소 정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFG 실행 후 저장소를 정리합니다.&lt;/p&gt;
&lt;pre class=&quot;brainfuck&quot;&gt;&lt;code&gt;git reflog expire --expire=now --all
git gc --prune=now --aggressive&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 변경사항 강제 푸시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변경된 내용을 강제로 푸시합니다.&lt;/p&gt;
&lt;pre class=&quot;brainfuck&quot;&gt;&lt;code&gt;git push origin --force --all
git push origin --force --tags&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. Git 최종 정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종적으로 저장소에서 민감 정보가 완전히 제거되었는지 확인 후, 추가적인 정리를 진행합니다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git push origin --force --all
git push origin --force --tags&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 참고 자료 및 결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 &lt;b&gt;GitLab에서 GitHub로 리포지토리를 미러링&lt;/b&gt;하면서 &lt;b&gt;민감 정보를 안전하게 제거&lt;/b&gt;하는 과정을 안내드렸습니다. 프로젝트를 공유하거나 협업하는 과정에서 민감한 정보가 노출되지 않도록 사전 조치를 취하는 것이 중요합니다.&lt;/p&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;b&gt;참고 자료&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://rtyley.github.io/bfg-repo-cleaner/&quot;&gt;BFG Repo-Cleaner 공식 사이트&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/doc&quot;&gt;Git 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;b&gt;주의 사항&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작업 전에 &lt;b&gt;백업&lt;/b&gt;을 권장합니다.&lt;/li&gt;
&lt;li&gt;민감 정보 제거 후 Git 히스토리에 변경사항이 정확히 적용되었는지 확인하세요.&lt;/li&gt;
&lt;/ul&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;/p&gt;</description>
      <category>Git</category>
      <category>bfg repo-cleaner</category>
      <category>GIT</category>
      <category>git 기록 정리</category>
      <category>github</category>
      <category>GitLab</category>
      <category>민감 정보 보호</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>422haha</author>
      <guid isPermaLink="true">https://dev-miyeon.tistory.com/3</guid>
      <comments>https://dev-miyeon.tistory.com/3#entry3comment</comments>
      <pubDate>Wed, 20 Nov 2024 15:47:19 +0900</pubDate>
    </item>
    <item>
      <title>GitLab에서 GitHub로 리포지토리 미러링</title>
      <link>https://dev-miyeon.tistory.com/2</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요! 이번 포스팅에서는 &lt;b&gt;GitLab&lt;/b&gt;에서 &lt;b&gt;GitHub&lt;/b&gt;으로 리포지토리를 미러링하는 방법에 대해 상세히 설명드리겠습니다. 프로젝트를 관리하거나 협업 환경을 GitHub으로 이전하고자 할 때 유용하게 활용할 수 있는 방법으로, GitLab과 GitHub의 기본적인 차이점부터 실제 미러링 과정까지 단계별로 안내해 드립니다. 초보자도 쉽게 따라 할 수 있도록 각 단계별 명령어와 설정 방법을 포함하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 프로젝트는 다양한 협업 도구와 플랫폼을 활용하여 효율적으로 개발을 진행하고 있습니다. 이번 포스팅을 통해 GitLab에서 GitHub으로의 원활한 이전 과정을 경험해보세요!&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#1-github%EC%97%90%EC%84%9C-private-%EB%A6%AC%ED%8F%AC%EC%A7%80%ED%86%A0%EB%A6%AC-%EC%83%9D%EC%84%B1&quot;&gt;GitHub에서 Private 리포지토리 생성&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#2-gitlab-%EB%A6%AC%ED%8F%AC%EC%A7%80%ED%86%A0%EB%A6%AC-%EB%AF%B8%EB%9F%AC%EB%A7%81%EC%9D%84-%EC%9C%84%ED%95%9C-%ED%81%B4%EB%A1%A0&quot;&gt;GitLab 리포지토리 미러링을 위한 클론&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#3-%ED%81%B4%EB%A1%A0%ED%95%9C-%ED%8F%B4%EB%8D%94%EB%A1%9C-%EC%9D%B4%EB%8F%99&quot;&gt;클론한 폴더로 이동&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#4-github%EC%9C%BC%EB%A1%9C-%EB%AF%B8%EB%9F%AC%EB%A7%81-%ED%91%B8%EC%8B%9C&quot;&gt;GitHub으로 미러링 푸시&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#5-github-%EC%84%A4%EC%A0%95%EC%97%90%EC%84%9C-default-branch-%ED%99%95%EC%9D%B8-%EB%B0%8F-%EB%B3%80%EA%B2%BD&quot;&gt;GitHub 설정에서 Default Branch 확인 및 변경&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#6-%EC%B6%94%EA%B0%80-%ED%8C%81-%EB%B0%8F-%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C&quot;&gt;추가 팁 및 참고 자료&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. GitHub에서 Private 리포지토리 생성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, GitHub에서 미러링할 대상인 Private 리포지토리를 생성합니다. Private 리포지토리는 공개되지 않으며, 권한이 있는 사용자만 접근할 수 있어 보안이 강화된 환경에서 프로젝트를 관리할 때 유용합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.1 GitHub 로그인&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;에 접속하여 계정에 로그인합니다.&lt;/li&gt;
&lt;li&gt;오른쪽 상단의 &lt;b&gt;+&lt;/b&gt; 아이콘을 클릭한 후 &lt;b&gt;New repository&lt;/b&gt;를 선택합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.2 리포지토리 생성&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Repository name&lt;/b&gt;: 원하는 리포지토리 이름을 입력합니다. 예: &lt;code&gt;Arcana&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Description&lt;/b&gt;: 리포지토리에 대한 간단한 설명을 추가합니다. (선택 사항)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Privacy&lt;/b&gt;: &lt;b&gt;Private&lt;/b&gt;을 선택하여 비공개 리포지토리를 생성합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Initialize this repository with a README&lt;/b&gt;: 초기화는 하지 않습니다. (기존 GitLab 리포지토리를 미러링하기 위해서는 초기화를 하지 않는 것이 좋습니다.)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Create repository&lt;/b&gt; 버튼을 클릭하여 리포지토리를 생성합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s0Fdw/btsKPTO1Co3/b1QY3dYufi4aDbSVeda1J1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s0Fdw/btsKPTO1Co3/b1QY3dYufi4aDbSVeda1J1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s0Fdw/btsKPTO1Co3/b1QY3dYufi4aDbSVeda1J1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs0Fdw%2FbtsKPTO1Co3%2Fb1QY3dYufi4aDbSVeda1J1%2Fimg.webp&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;2048&quot; height=&quot;1280&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1280&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. GitLab 리포지토리 미러링을 위한 클론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 GitLab에 존재하는 리포지토리를 미러링하기 위해 클론을 수행합니다. &lt;code&gt;--mirror&lt;/code&gt; 옵션을 사용하면 모든 브랜치와 태그, 그리고 리모트 설정까지 포함한 완전한 미러링을 할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 GitLab 리포지토리 클론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널을 열고 다음 명령어를 입력하여 GitLab 리포지토리를 미러링 클론합니다:&lt;/p&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;git clone --mirror https://lab.ssafy.com/s11-final/S11P31D103.git&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;git clone --mirror&lt;/code&gt;: 리포지토리의 모든 내용을 미러링하여 클론합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://lab.ssafy.com/s11-final/S11P31D103.git&lt;/code&gt;: 클론하려는 GitLab 리포지토리의 URL입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클론이 완료되면 &lt;code&gt;S11P31D103.git&lt;/code&gt;이라는 폴더가 생성됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 클론한 폴더로 이동&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클론한 리포지토리 폴더로 이동하여 다음 단계를 진행합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 폴더 이동 명령어&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;cd S11P31D103.git&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;cd S11P31D103.git&lt;/code&gt;: 클론한 리포지토리 폴더로 이동합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 GitLab 리포지토리의 모든 내용이 로컬에 미러링되어 저장되었습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. GitHub으로 미러링 푸시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미러링된 리포지토리를 GitHub의 Private 리포지토리로 푸시하여 이전을 완료합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1 GitHub 리포지토리로 푸시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 명령어를 입력하여 미러링된 리포지토리를 GitHub으로 푸시합니다:&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;git push --mirror https://github.com/422haha/Arcana.git&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;git push --mirror&lt;/code&gt;: 모든 브랜치와 태그, 리모트 설정을 포함하여 푸시합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://github.com/422haha/Arcana.git&lt;/code&gt;: 푸시할 GitHub 리포지토리의 URL입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의 사항&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GitHub 리포지토리는 미리 생성되어 있어야 합니다.&lt;/li&gt;
&lt;li&gt;푸시 과정에서 GitHub 계정의 인증 정보(아이디 및 패스워드 또는 토큰)를 입력해야 할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. GitHub 설정에서 Default Branch 확인 및 변경&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미러링이 완료된 후, GitHub 리포지토리의 기본 브랜치(Default Branch)를 확인하고 필요에 따라 변경합니다. 기본 브랜치는 새로 푸시된 리포지토리에서 자동으로 설정되지만, 특정 브랜치를 기본으로 지정하고 싶을 경우 변경할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1 GitHub 리포지토리 접속&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;웹 브라우저에서 &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;에 접속합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;422haha&lt;/b&gt; 사용자 계정의 &lt;b&gt;Arcana&lt;/b&gt; 리포지토리를 엽니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FGUiC/btsKQBtpCoq/nB7HbpMfAcJTfABvLYcYs1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FGUiC/btsKQBtpCoq/nB7HbpMfAcJTfABvLYcYs1/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FGUiC/btsKQBtpCoq/nB7HbpMfAcJTfABvLYcYs1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFGUiC%2FbtsKQBtpCoq%2FnB7HbpMfAcJTfABvLYcYs1%2Fimg.webp&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;2048&quot; height=&quot;1280&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.2 기본 브랜치 확인 및 변경&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;리포지토리 메인 페이지에서 오른쪽 상단의 &lt;b&gt;Settings&lt;/b&gt; 탭을 클릭합니다.&lt;/li&gt;
&lt;li&gt;좌측 사이드바에서 &lt;b&gt;Branches&lt;/b&gt;를 선택합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Default branch&lt;/b&gt; 섹션에서 현재 설정된 기본 브랜치를 확인할 수 있습니다.&lt;/li&gt;
&lt;li&gt;기본 브랜치를 변경하고 싶다면 &lt;b&gt;Change default branch&lt;/b&gt; 버튼을 클릭하여 원하는 브랜치를 선택합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v4Dpg/btsKOnYcJyu/2yKlJB57xDNUuXhOfZBiT0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v4Dpg/btsKOnYcJyu/2yKlJB57xDNUuXhOfZBiT0/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v4Dpg/btsKOnYcJyu/2yKlJB57xDNUuXhOfZBiT0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv4Dpg%2FbtsKOnYcJyu%2F2yKlJB57xDNUuXhOfZBiT0%2Fimg.webp&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;2048&quot; height=&quot;1280&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;1280&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Default branch&lt;/b&gt;: 리포지토리의 기본 브랜치를 설정합니다. 새로운 풀 리퀘스트나 이슈가 생성될 때 기본적으로 참조되는 브랜치입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Change default branch&lt;/b&gt;: 기본 브랜치를 변경할 수 있는 옵션입니다.&lt;/li&gt;
&lt;/ul&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;b&gt;GitLab&lt;/b&gt;에서 &lt;b&gt;GitHub&lt;/b&gt;으로 리포지토리를 미러링하는 과정을 단계별로 상세히 설명드렸습니다. GitLab과 GitHub은 각각의 장점이 있으므로, 프로젝트의 요구 사항에 맞게 적절한 플랫폼을 선택하고, 원활한 이전 과정을 통해 효율적인 협업 환경을 구축하시기 바랍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다!&lt;/p&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;b&gt;참고 자료&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs&quot;&gt;Git 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/&quot;&gt;GitHub 공식 사이트&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gitlab.com/&quot;&gt;GitLab 공식 사이트&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;b&gt;주의 사항&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;민감한 정보(비밀번호, API 키 등)는 절대로 공개하지 않도록 주의하세요.&lt;/li&gt;
&lt;li&gt;리포지토리 미러링 시 데이터 손실을 방지하기 위해 사전에 백업을 권장드립니다.&lt;/li&gt;
&lt;li&gt;실제 운영 환경에서는 보안 설정을 더욱 강화하고, 권한 관리를 철저히 해야 합니다.&lt;/li&gt;
&lt;/ul&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;이제 GitLab에서 GitHub으로의 리포지토리 미러링을 통해 보다 유연하고 효율적인 협업 환경을 경험해보세요!&lt;/p&gt;</description>
      <category>Git</category>
      <category>git 사용법</category>
      <category>github</category>
      <category>GitLab</category>
      <category>gitlab to github</category>
      <category>리포지토리 미러링</category>
      <category>미러링</category>
      <category>프로젝트 관리</category>
      <author>422haha</author>
      <guid isPermaLink="true">https://dev-miyeon.tistory.com/2</guid>
      <comments>https://dev-miyeon.tistory.com/2#entry2comment</comments>
      <pubDate>Wed, 20 Nov 2024 14:19:43 +0900</pubDate>
    </item>
    <item>
      <title>CI/CD 무중단 배포 구현 가이드: 블루-그린 배포를 통한 안정적인 애플리케이션 업데이트</title>
      <link>https://dev-miyeon.tistory.com/1</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요! 이번 포스팅에서는 &lt;b&gt;CI/CD 파이프라인&lt;/b&gt;을 구축하고 &lt;b&gt;블루-그린 배포&lt;/b&gt; 방식을 적용하여 &lt;b&gt;무중단 배포&lt;/b&gt;를 구현한 과정을 상세히 공유하고자 합니다. 이 글은 CI/CD를 처음 접하시는 분들도 따라 할 수 있도록 각 단계별로 명령어와 설정 파일을 포함하고 있으며, 필요한 개념에 대한 설명과 파일 생성 및 수정 방법까지 함께 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 프로젝트는 자연 탐험과 학습을 돕기 위한 게이미피케이션 기반의 AR/AI 동식물 탐험 애플리케이션인 &lt;b&gt;&quot;이게모야&quot;&lt;/b&gt;입니다. 이번 포스팅을 통해 CI/CD 구축 과정에서 사용한 도구와 기술, 그리고 그 선택 이유를 자세히 설명하겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#1-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%86%8C%EA%B0%9C&quot;&gt;프로젝트 소개&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#2-cicd-%EB%B0%8F-%EB%B8%94%EB%A3%A8-%EA%B7%B8%EB%A6%B0-%EB%B0%B0%ED%8F%AC%EB%9E%80&quot;&gt;CI/CD 및 블루-그린 배포란?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#3-%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95-%EB%B0%8F-%EC%B4%88%EA%B8%B0-%EA%B5%AC%EC%84%B1&quot;&gt;환경 설정 및 초기 구성&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#4-docker-%EB%B0%8F-docker-compose-%EC%84%A4%EC%B9%98&quot;&gt;Docker 및 Docker Compose 설치&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#5-dockerhub-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0&quot;&gt;DockerHub 이해하기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#6-jenkins-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%84%A4%EC%A0%95&quot;&gt;Jenkins 설치 및 설정&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#7-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EB%B0%8F-%EC%BA%90%EC%8B%9C-%EC%84%9C%EB%B2%84-%EC%84%A4%EC%B9%98&quot;&gt;데이터베이스 및 캐시 서버 설치&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-docker%ED%99%94-%EB%B0%8F-docker-compose-%ED%8C%8C%EC%9D%BC-%EC%9E%91%EC%84%B1&quot;&gt;프로젝트 Docker화 및 Docker Compose 파일 작성&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#9-nginx-%EC%84%A4%EC%A0%95-%EB%B0%8F-%EB%AC%B4%EC%A4%91%EB%8B%A8-%EB%B0%B0%ED%8F%AC-%EA%B5%AC%ED%98%84&quot;&gt;Nginx 설정 및 무중단 배포 구현&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#10-jenkins-%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8-%EC%84%A4%EC%A0%95&quot;&gt;Jenkins 파이프라인 설정&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#11-sonarqube%EB%A5%BC-%ED%86%B5%ED%95%9C-%EC%BD%94%EB%93%9C-%ED%92%88%EC%A7%88-%EA%B4%80%EB%A6%AC&quot;&gt;SonarQube를 통한 코드 품질 관리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#12-%EB%B3%B4%EC%95%88-%EA%B0%95%ED%99%94-%EC%84%A4%EC%A0%95-fail2ban-%EB%B0%8F-modsecurity&quot;&gt;보안 강화 설정 (Fail2Ban 및 ModSecurity)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#13-%EB%A7%88%EB%AC%B4%EB%A6%AC-%EB%B0%8F-%EA%B0%9C%EC%84%A0-%EC%82%AC%ED%95%AD&quot;&gt;마무리 및 개선 사항&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 프로젝트 소개&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;이게모야&quot;&lt;/b&gt;는 사용자가 실제 공원을 탐험하며 동식물 정보를 수집하고, AR 기술과 AI를 활용하여 자연과 상호작용할 수 있는 애플리케이션입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;주요 기능&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;온디바이스 AI 기반 실시간 동식물 판별&lt;/b&gt;: 사용자가 촬영한 동식물 이미지를 기기 내에서 AI 모델을 통해 실시간으로 판별합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AR을 활용한 네비게이션&lt;/b&gt;: AR 기술을 통해 공원 내에서 사용자에게 길 안내 및 위치 정보를 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;LLM(대규모 언어 모델)을 활용한 동식물 정보 제공&lt;/b&gt;: 사용자가 질문하면 AI가 동식물에 대한 상세 정보를 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Redis를 활용한 실시간 데이터 캐싱&lt;/b&gt;: 사용자의 위치 데이터와 탐험 정보를 빠르게 처리하기 위해 Redis를 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. CI/CD 및 블루-그린 배포란?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CI/CD란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CI/CD&lt;/b&gt;는 &lt;b&gt;Continuous Integration (지속적 통합)&lt;/b&gt;과 &lt;b&gt;Continuous Deployment/Delivery (지속적 배포/전달)&lt;/b&gt;의 약어로, 소프트웨어 개발과 배포 과정을 자동화하여 효율성과 품질을 높이는 방법론입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Continuous Integration (CI)&lt;/b&gt;: 개발자들이 코드 변경 사항을 중앙 저장소에 자주 병합하여 자동으로 빌드하고 테스트하는 프로세스입니다. 이를 통해 코드의 품질을 유지하고, 통합 과정에서 발생할 수 있는 문제를 조기에 발견할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Continuous Deployment/Delivery (CD)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Continuous Delivery&lt;/b&gt;: 자동화된 테스트를 거친 코드를 프로덕션 환경에 배포할 준비를 하는 단계입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Continuous Deployment&lt;/b&gt;: 테스트를 모두 통과한 코드를 자동으로 프로덕션 환경에 배포하는 단계입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CI/CD의 장점&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;빠른 피드백 루프&lt;/b&gt;: 코드 변경 사항이 즉시 빌드되고 테스트되므로 문제를 빠르게 발견하고 해결할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자동화된 배포&lt;/b&gt;: 배포 과정을 자동화하여 인적 오류를 줄이고, 배포 속도를 향상시킵니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;지속적인 개선&lt;/b&gt;: 지속적인 통합과 배포를 통해 소프트웨어의 지속적인 개선과 업데이트가 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;블루-그린 배포란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;블루-그린 배포&lt;/b&gt;는 두 개의 동일한 운영 환경(블루, 그린)을 사용하여 애플리케이션을 배포하는 방식입니다. 이를 통해 무중단 배포를 실현할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;블루 환경&lt;/b&gt;: 현재 프로덕션에서 서비스 중인 환경입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;그린 환경&lt;/b&gt;: 새로운 버전의 애플리케이션을 배포하는 환경입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;배포 과정&lt;/b&gt;:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;새로운 버전을 그린 환경에 배포하고 테스트합니다.&lt;/li&gt;
&lt;li&gt;문제가 없으면 트래픽을 블루에서 그린으로 전환합니다.&lt;/li&gt;
&lt;li&gt;이전 버전(블루 환경)은 대기 상태로 유지하거나 제거합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;무중단 배포&lt;/b&gt;: 사용자에게 서비스 중단 없이 새로운 버전을 제공할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;빠른 롤백&lt;/b&gt;: 문제가 발생할 경우, 이전 환경으로 빠르게 전환하여 롤백할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 환경 설정 및 초기 구성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CI/CD 구축을 위해 먼저 서버 환경을 설정하고 초기 구성을 진행해야 합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) 서버 접속 및 기본 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS EC2 인스턴스(Ubuntu 20.04 LTS)에 접속하여 기본적인 업데이트와 설정을 진행합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1 서버 업데이트 및 업그레이드&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# 서버 업데이트 및 업그레이드
sudo apt update
sudo apt upgrade -y&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;sudo apt update&lt;/code&gt;: 패키지 목록을 업데이트합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo apt upgrade -y&lt;/code&gt;: 설치된 패키지를 최신 버전으로 업그레이드합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2 필수 빌드 도구 설치&lt;/h4&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;# 필수 빌드 도구 설치
sudo apt install -y build-essential&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;sudo apt install -y build-essential&lt;/code&gt;: 빌드에 필요한 도구들을 설치합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3 시간대를 한국 시간대로 설정&lt;/h4&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;# 시간대를 한국 시간대로 설정
sudo ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime

# 시간 확인
date&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;sudo ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime&lt;/code&gt;: 서버의 시간대를 한국 시간대로 설정합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;date&lt;/code&gt;: 현재 서버의 시간을 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) 사용자 권한 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker 명령을 사용할 때 매번 &lt;code&gt;sudo&lt;/code&gt;를 사용하지 않도록 현재 사용자를 Docker 그룹에 추가합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1 현재 사용자 Docker 그룹에 추가&lt;/h4&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;# 현재 사용자 Docker 그룹에 추가
sudo usermod -aG docker $USER&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;sudo usermod -aG docker $USER&lt;/code&gt;: 현재 사용자를 Docker 그룹에 추가하여 Docker 명령을 &lt;code&gt;sudo&lt;/code&gt; 없이 실행할 수 있게 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2 변경 사항 적용을 위해 로그아웃 후 재로그인&lt;/h4&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;# 현재 세션에서 로그아웃
exit&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;변경 사항을 적용하기 위해 현재 SSH 세션에서 로그아웃하고 다시 로그인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Docker 및 Docker Compose 설치&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker는 애플리케이션을 컨테이너화하여 일관된 환경에서 실행할 수 있게 해줍니다. Docker Compose는 여러 개의 Docker 컨테이너를 정의하고 실행할 수 있게 해주는 도구입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) Docker 설치&lt;/h3&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# 필요한 패키지 설치
sudo apt-get update
sudo apt-get install -y \
  ca-certificates \
  curl \
  gnupg \
  lsb-release&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker 설치에 필요한 패키지들을 설치합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2 Docker의 공식 GPG 키 추가&lt;/h4&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;# Docker의 공식 GPG 키 추가
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker 공식 GPG 키를 추가하여 패키지의 신뢰성을 확보합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3 Docker 저장소 추가&lt;/h4&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;# Docker 저장소 추가
echo \
  &quot;deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
  https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable&quot; | sudo tee /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker 저장소를 추가합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.4 Docker 엔진 설치&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# Docker 엔진 설치
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker 엔진을 설치합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.5 Docker 설치 확인&lt;/h4&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;# Docker 버전 확인
docker --version&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설치된 Docker의 버전을 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) Docker Compose 설치&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;sudo apt-get install -y docker-compose&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;docker-compose&lt;/code&gt;는 여러 Docker 컨테이너를 정의하고 관리하는 데 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;설치 확인&lt;/h4&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;docker-compose --version&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. DockerHub 이해하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DockerHub&lt;/b&gt;는 Docker 컨테이너 이미지를 저장하고 공유할 수 있는 클라우드 기반 레지스트리 서비스입니다. 개발자들은 DockerHub를 통해 자신이 만든 이미지를 업로드하고, 다른 사람들이 이를 다운로드하여 사용할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DockerHub의 주요 기능&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;이미지 저장소&lt;/b&gt;: Docker 이미지를 저장하고 관리할 수 있는 공간을 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공개 및 비공개 저장소&lt;/b&gt;: 공개 저장소를 통해 누구나 이미지를 볼 수 있으며, 비공개 저장소를 통해 특정 사용자만 접근할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자동 빌드&lt;/b&gt;: GitHub나 Bitbucket과 연동하여 코드 변경 시 자동으로 Docker 이미지를 빌드할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;협업 기능&lt;/b&gt;: 팀 단위로 이미지를 관리하고 협업할 수 있는 기능을 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DockerHub 사용 이유&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;손쉬운 이미지 배포&lt;/b&gt;: 전 세계 어디서나 접근 가능한 중앙 저장소를 통해 이미지를 쉽게 배포하고 공유할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자동화된 워크플로우&lt;/b&gt;: 자동 빌드와 연동 기능을 통해 CI/CD 파이프라인과 원활하게 통합할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;버전 관리&lt;/b&gt;: 이미지의 다양한 버전을 관리하고 추적할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DockerHub 계정 생성 및 이미지 푸시&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.1 DockerHub 계정 생성&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://hub.docker.com/&quot;&gt;DockerHub&lt;/a&gt;에 접속하여 계정을 생성합니다.&lt;/li&gt;
&lt;li&gt;계정을 생성한 후, 로그인합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.2 로컬에서 Docker 이미지 빌드 및 DockerHub에 푸시&lt;/h4&gt;
&lt;h5&gt;5.2.1 DockerHub에 로그인&lt;/h5&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;# DockerHub에 로그인
docker login -u your_dockerhub_username -p your_dockerhub_password&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DockerHub에 로그인하여 인증을 받습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;5.2.2 Docker 이미지 태깅&lt;/h5&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;# Docker 이미지 태깅
docker tag your_image:latest your_dockerhub_username/moya:latest&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬에서 빌드한 이미지를 DockerHub에 업로드할 수 있도록 태깅합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;5.2.3 DockerHub에 이미지 푸시&lt;/h5&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;# DockerHub에 이미지 푸시
docker push your_dockerhub_username/moya:latest&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;태깅한 이미지를 DockerHub에 푸시하여 저장소에 업로드합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DockerHub의 저장소 이름은 &lt;code&gt;your_dockerhub_username/repository_name:tag&lt;/code&gt; 형식을 따릅니다.&lt;/li&gt;
&lt;li&gt;개인 프로젝트는 비공개 저장소로 설정할 수 있으며, 팀 프로젝트는 협업 기능을 활용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. Jenkins 설치 및 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Jenkins&lt;/b&gt;는 오픈 소스 자동화 서버로, CI/CD 파이프라인을 구축하는 데 사용됩니다. Jenkins를 사용하면 코드의 빌드, 테스트, 배포 과정을 자동화할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) Jenkins 설치&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.1 Jenkins 데이터 저장 디렉토리 생성&lt;/h4&gt;
&lt;pre class=&quot;hsp&quot;&gt;&lt;code&gt;# Jenkins 데이터 저장 디렉토리 생성
mkdir -p ~/jenkins&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Jenkins 데이터를 호스트의 &lt;code&gt;~/jenkins&lt;/code&gt; 디렉토리에 저장하여 컨테이너 재시작 시 데이터 유실을 방지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.2 Jenkins 컨테이너 실행&lt;/h4&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;# Jenkins 컨테이너 실행
sudo docker run -d \
  -p 9090:8080 \
  -p 50000:50000 \
  --name jenkins \
  -v ~/jenkins:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  jenkins/jenkins:jdk17&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;-p 9090:8080&lt;/code&gt;: 호스트의 9090 포트를 컨테이너의 8080 포트에 매핑하여 Jenkins UI에 접근할 수 있게 합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p 50000:50000&lt;/code&gt;: Jenkins 에이전트 통신을 위한 포트를 매핑합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v ~/jenkins:/var/jenkins_home&lt;/code&gt;: Jenkins 데이터를 호스트의 &lt;code&gt;~/jenkins&lt;/code&gt; 디렉토리에 저장합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v /var/run/docker.sock:/var/run/docker.sock&lt;/code&gt;: Jenkins가 Docker를 제어할 수 있도록 Docker 소켓을 마운트합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) Jenkins 초기 설정&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.3 Jenkins 초기 비밀번호 확인&lt;/h4&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;# Jenkins 초기 비밀번호 확인
sudo docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초기 비밀번호를 확인한 후, 웹 브라우저에서 &lt;code&gt;http://[서버 IP]:9090&lt;/code&gt;으로 접속하여 Jenkins 초기 설정을 완료합니다.&lt;/li&gt;
&lt;li&gt;기본 계정(&lt;code&gt;admin&lt;/code&gt;)으로 로그인하고, 비밀번호를 변경합니다.&lt;/li&gt;
&lt;li&gt;필요한 플러그인들을 설치합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) Jenkins에서 Docker 사용 권한 설정&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.4 Jenkins 컨테이너에서 root 사용자로 접속&lt;/h4&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;# Jenkins 컨테이너에서 root 사용자로 접속
sudo docker exec -it --user root jenkins bash&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Jenkins 컨테이너에 root 사용자로 접속하여 Docker 그룹에 Jenkins 사용자를 추가합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.5 Docker 그룹에 Jenkins 사용자 추가&lt;/h4&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;# Docker 그룹에 Jenkins 사용자 추가
usermod -aG docker jenkins&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;usermod -aG docker jenkins&lt;/code&gt;: Jenkins 사용자를 Docker 그룹에 추가하여 Docker 명령을 &lt;code&gt;sudo&lt;/code&gt; 없이 실행할 수 있게 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.6 컨테이너에서 나와 Jenkins 재시작&lt;/h4&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;# 컨테이너에서 나와 Jenkins 재시작
exit
sudo docker restart jenkins&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너에서 나와 Jenkins를 재시작하여 변경 사항을 적용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4) Maven 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jenkins에서 Maven 빌드를 수행하기 위해 Maven을 설치합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.7 Jenkins 컨테이너에서 root 사용자로 접속&lt;/h4&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;# Jenkins 컨테이너에서 root 사용자로 접속
sudo docker exec -it --user root jenkins bash&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.8 Maven 설치&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# Maven 설치
apt-get update
apt-get install -y maven&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Maven을 설치하여 Java 프로젝트를 빌드할 수 있게 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.9 Maven 설치 디렉토리 권한 설정&lt;/h4&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;# Maven 설치 디렉토리 권한 설정
chown -R jenkins:jenkins /usr/share/maven&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Maven 디렉토리의 소유권을 Jenkins 사용자로 변경하여 권한 문제를 방지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.10 Maven 버전 확인&lt;/h4&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# Maven 버전 확인
su jenkins
mvn --version&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Maven이 올바르게 설치되었는지 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.11 컨테이너에서 나와 Jenkins 재시작&lt;/h4&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;# 컨테이너에서 나와 Jenkins 재시작
exit
sudo docker restart jenkins&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너에서 나와 Jenkins를 재시작하여 변경 사항을 적용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 데이터베이스 및 캐시 서버 설치&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션의 데이터 저장과 빠른 데이터 접근을 위해 PostgreSQL과 Redis를 설치합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) PostgreSQL 설치 및 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PostgreSQL&lt;/b&gt;은 강력한 오픈 소스 관계형 데이터베이스 관리 시스템입니다. &lt;b&gt;PostGIS&lt;/b&gt;는 PostgreSQL의 공간 확장 모듈로, 지리 공간 데이터를 처리할 수 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;7.1 PostgreSQL Docker 컨테이너 실행&lt;/h4&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;# PostgreSQL Docker 컨테이너 실행
docker run -d \
  -p 5432:5432 \
  -v /var/lib/postgres-data:/var/lib/postgresql/data \
  --name postgres \
  -e POSTGRES_PASSWORD=your_password \
  postgres:14&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;-p 5432:5432&lt;/code&gt;: 호스트의 5432 포트를 컨테이너의 5432 포트에 매핑합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v /var/lib/postgres-data:/var/lib/postgresql/data&lt;/code&gt;: 데이터 지속성을 위해 호스트의 디렉토리를 마운트합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-e POSTGRES_PASSWORD=your_password&lt;/code&gt;: PostgreSQL의 &lt;code&gt;postgres&lt;/code&gt; 사용자 비밀번호를 설정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;7.2 PostGIS 확장 설치&lt;/h4&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;# PostgreSQL 컨테이너에 접속
docker exec -it postgres bash&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PostgreSQL 컨테이너에 접속하여 PostGIS를 설치합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# 패키지 목록 업데이트 및 PostGIS 설치
apt-get update
apt-get install -y postgis postgresql-14-postgis-3&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PostGIS 확장을 설치하여 공간 데이터를 처리할 수 있게 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;# PostgreSQL에 접속
psql -U postgres&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PostgreSQL에 접속하여 데이터베이스를 생성하고 확장을 추가합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;-- 데이터베이스 생성
CREATE DATABASE moya;

-- moya 데이터베이스로 전환
\c moya

-- PostGIS 확장 추가
CREATE EXTENSION postgis;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;CREATE DATABASE moya;&lt;/code&gt;: &lt;code&gt;moya&lt;/code&gt;라는 이름의 데이터베이스를 생성합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\c moya&lt;/code&gt;: &lt;code&gt;moya&lt;/code&gt; 데이터베이스로 전환합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CREATE EXTENSION postgis;&lt;/code&gt;: &lt;code&gt;moya&lt;/code&gt; 데이터베이스에 PostGIS 확장을 추가합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;# PostgreSQL 컨테이너에서 나가기
exit&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;7.3 PostgreSQL 설정 파일 위치 확인 및 권한 설정&lt;/h4&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;# PostgreSQL 데이터 디렉토리 권한 확인
ls -la /var/lib/postgresql/data&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 디렉토리의 권한을 확인하여 데이터가 안전하게 저장되고 있는지 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) Redis 설치&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Redis&lt;/b&gt;는 빠른 메모리 기반의 키-값 저장소로, 실시간 데이터 캐싱에 적합합니다.&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;# Redis Docker 컨테이너 실행
docker run -d \
  -p 6379:6379 \
  -v /var/lib/redis-data:/data \
  --name redis \
  redis:latest&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;-p 6379:6379&lt;/code&gt;: 호스트의 6379 포트를 컨테이너의 6379 포트에 매핑합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-v /var/lib/redis-data:/data&lt;/code&gt;: 데이터 지속성을 위해 호스트의 디렉토리를 마운트합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 프로젝트 Docker화 및 Docker Compose 파일 작성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트를 Docker 컨테이너화하여 일관된 환경에서 실행할 수 있도록 설정합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) 프로젝트 Dockerfile 작성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot 애플리케이션을 Docker 이미지로 빌드하기 위한 &lt;code&gt;Dockerfile&lt;/code&gt;을 작성합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1 &lt;code&gt;Dockerfile&lt;/code&gt; 생성 및 편집&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;파일 생성 위치&lt;/b&gt;: 프로젝트의 &lt;code&gt;backend&lt;/code&gt; 디렉토리 내에 &lt;code&gt;Dockerfile&lt;/code&gt;을 생성합니다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# backend 디렉토리로 이동
cd backend

# Dockerfile 생성 및 편집
nano Dockerfile&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;cd backend&lt;/code&gt;: &lt;code&gt;backend&lt;/code&gt; 디렉토리로 이동합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nano Dockerfile&lt;/code&gt;: &lt;code&gt;Dockerfile&lt;/code&gt;을 생성하고 편집합니다. (&lt;code&gt;nano&lt;/code&gt; 대신 &lt;code&gt;vi&lt;/code&gt;, &lt;code&gt;vim&lt;/code&gt; 등 다른 편집기를 사용할 수도 있습니다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2 &lt;code&gt;Dockerfile&lt;/code&gt; 내용 복사 및 저장&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Dockerfile&lt;/code&gt;에 다음 내용을 복사하여 붙여넣습니다:&lt;/p&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;# backend/Dockerfile

# OpenJDK 17 슬림 버전 사용
FROM openjdk:17-jdk-slim

# 작업 디렉토리 설정
WORKDIR /app

# 필요한 패키지 설치
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y curl

# 시간대 설정
RUN ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime

# 애플리케이션 JAR 파일 복사
COPY target/moya-0.0.1-SNAPSHOT.jar app.jar

# 환경 변수 파일 복사
COPY .env .env

# Spring Boot 설정 파일 복사
COPY src/main/resources/application.properties application.properties
COPY src/main/resources/application-oauth-kakao.properties application-oauth-kakao.properties
COPY src/main/resources/application-oauth-naver.properties application-oauth-naver.properties

# 애플리케이션 실행
ENTRYPOINT [&quot;java&quot;, &quot;-jar&quot;, &quot;app.jar&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Base Image&lt;/b&gt;: OpenJDK 17 슬림 버전을 사용하여 Java 애플리케이션을 실행할 환경을 구성합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;WORKDIR&lt;/b&gt;: 컨테이너 내 작업 디렉토리를 &lt;code&gt;/app&lt;/code&gt;으로 설정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;RUN&lt;/b&gt;: 필요한 패키지인 &lt;code&gt;curl&lt;/code&gt;을 설치하고, 시간대를 한국 시간대로 설정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;COPY&lt;/b&gt;: 빌드된 JAR 파일과 환경 변수 파일, Spring Boot 설정 파일들을 컨테이너로 복사합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ENTRYPOINT&lt;/b&gt;: 애플리케이션을 실행하는 명령어를 설정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3 &lt;code&gt;Dockerfile&lt;/code&gt; 저장 및 종료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Nano&lt;/b&gt;에서 저장: &lt;code&gt;Ctrl + O&lt;/code&gt;, &lt;code&gt;Enter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Nano&lt;/b&gt;에서 종료: &lt;code&gt;Ctrl + X&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) Docker Compose 파일 작성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블루-그린 배포를 위한 &lt;code&gt;docker-compose.yml&lt;/code&gt; 파일을 작성합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1 &lt;code&gt;docker-compose.yml&lt;/code&gt; 생성 및 편집&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;파일 생성 위치&lt;/b&gt;: 프로젝트의 &lt;code&gt;backend&lt;/code&gt; 디렉토리 내에 &lt;code&gt;docker-compose.yml&lt;/code&gt; 파일을 생성합니다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# backend 디렉토리로 이동
cd backend

# docker-compose.yml 파일 생성 및 편집
nano docker-compose.yml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;cd backend&lt;/code&gt;: &lt;code&gt;backend&lt;/code&gt; 디렉토리로 이동합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nano docker-compose.yml&lt;/code&gt;: &lt;code&gt;docker-compose.yml&lt;/code&gt; 파일을 생성하고 편집합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2 &lt;code&gt;docker-compose.yml&lt;/code&gt; 내용 복사 및 저장&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;에 다음 내용을 복사하여 붙여넣습니다:&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;# backend/docker-compose.yml

version: '3.8'

services:
  springboot-blue:
    image: your_dockerhub_username/moya:blue
    container_name: springboot-blue
    ports:
      - &quot;8081:8080&quot;
    env_file:
      - .env
    environment:
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - TZ=Asia/Seoul
    networks:
      - app-network
    restart: unless-stopped

  springboot-green:
    image: your_dockerhub_username/moya:green
    container_name: springboot-green
    ports:
      - &quot;8082:8080&quot;
    env_file:
      - .env
    environment:
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - TZ=Asia/Seoul
    networks:
      - app-network
    restart: unless-stopped

  redis:
    image: redis:latest
    container_name: redis
    ports:
      - &quot;6379:6379&quot;
    networks:
      - app-network
    restart: unless-stopped

  sonarqube:
    image: sonarqube:latest
    container_name: sonarqube
    ports:
      - &quot;9000:9000&quot;
    networks:
      - app-network
    restart: unless-stopped

  postgres:
    image: postgres:14
    container_name: postgres
    ports:
      - &quot;5432:5432&quot;
    volumes:
      - /var/lib/postgres-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=your_password
    networks:
      - app-network
    restart: unless-stopped

  jenkins:
    image: jenkins/jenkins:jdk17
    container_name: jenkins
    ports:
      - &quot;9090:8080&quot;
      - &quot;50000:50000&quot;
    volumes:
      - ~/jenkins:/var/jenkins_home
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - app-network
    restart: unless-stopped

networks:
  app-network:
    driver: bridge&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Services&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;springboot-blue&lt;/code&gt; 및 &lt;code&gt;springboot-green&lt;/code&gt;: 블루-그린 배포를 위한 두 개의 Spring Boot 애플리케이션 인스턴스입니다. 각기 다른 포트(8081, 8082)를 사용하여 동시에 실행됩니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;redis&lt;/code&gt;: 캐시 서버로 사용됩니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sonarqube&lt;/code&gt;: 코드 품질 분석 도구인 SonarQube를 실행합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;postgres&lt;/code&gt;: PostgreSQL 데이터베이스 서버를 실행합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jenkins&lt;/code&gt;: CI/CD 파이프라인을 관리하는 Jenkins 서버입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Networks&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;app-network&lt;/code&gt;: 모든 서비스가 동일한 네트워크 내에서 통신할 수 있도록 설정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3 &lt;code&gt;docker-compose.yml&lt;/code&gt; 저장 및 종료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Nano&lt;/b&gt;에서 저장: &lt;code&gt;Ctrl + O&lt;/code&gt;, &lt;code&gt;Enter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Nano&lt;/b&gt;에서 종료: &lt;code&gt;Ctrl + X&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) Docker Compose 실행&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# backend 디렉토리로 이동
cd backend

# Docker Compose 실행
docker-compose up -d&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;docker-compose up -d&lt;/code&gt;: 백그라운드에서 모든 서비스를 실행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4) 현재 Docker 컨테이너 상태 확인&lt;/h3&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;docker ps -a&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;출력 결과 예시&lt;/b&gt;:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;CONTAINER ID   IMAGE                         COMMAND                  CREATED        STATUS        PORTS                                       NAMES
ba605bb2fc66   your_dockerhub_username/moya:blue           &quot;java -jar app.jar&quot;      2 days ago     Up 2 days     0.0.0.0:8081-&amp;gt;8080/tcp                      springboot-blue
bbb8bb79563b   your_dockerhub_username/moya:green          &quot;java -jar app.jar&quot;      2 days ago     Up 2 days     0.0.0.0:8082-&amp;gt;8080/tcp                      springboot-green
3e789de5ad79   postgres:14                   &quot;docker-entrypoint.s&amp;hellip;&quot;   2 weeks ago    Up 2 weeks    0.0.0.0:5432-&amp;gt;5432/tcp                      postgres
d57bb671e670   redis:latest                  &quot;docker-entrypoint.s&amp;hellip;&quot;   2 weeks ago    Up 2 weeks    0.0.0.0:6379-&amp;gt;6379/tcp                      redis
7f31b90ff248   sonarqube:latest              &quot;/opt/sonarqube/dock&amp;hellip;&quot;   2 weeks ago    Up 2 weeks    0.0.0.0:9000-&amp;gt;9000/tcp                      sonarqube
b22097030b69   jenkins/jenkins:jdk17         &quot;/usr/bin/tini -- /u&amp;hellip;&quot;   4 weeks ago    Up 2 weeks    0.0.0.0:9090-&amp;gt;8080/tcp, 0.0.0.0:50000-&amp;gt;50000/tcp  jenkins&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 컨테이너가 정상적으로 실행되고 있는지 확인합니다.&lt;/li&gt;
&lt;li&gt;포트 매핑을 통해 외부에서 서비스에 접근할 수 있는지 확인할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. Nginx 설정 및 무중단 배포 구현&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Nginx&lt;/b&gt;는 리버스 프록시 서버로, 트래픽을 블루 또는 그린 환경으로 라우팅하여 무중단 배포를 구현합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) Nginx 설치 및 SSL 인증서 발급&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1 Nginx 설치&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# Nginx 설치
sudo apt-get update
sudo apt-get install nginx -y&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹 서버인 Nginx를 설치합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2 UFW 방화벽 설정 (필요 시)&lt;/h4&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# UFW 방화벽에서 Nginx 트래픽 허용
sudo ufw allow 'Nginx Full'

# UFW 방화벽 활성화
sudo ufw enable&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UFW 방화벽을 사용 중이라면 Nginx 트래픽을 허용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3 Let's Encrypt 설치 및 SSL 인증서 발급&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# Let's Encrypt 및 Certbot 설치
sudo apt-get install certbot python3-certbot-nginx -y&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;무료 SSL 인증서를 발급받기 위한 Certbot을 설치합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;# SSL 인증서 발급 및 Nginx 설정 자동 업데이트
sudo certbot --nginx -d yourdomain.com&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;yourdomain.com&lt;/code&gt;을 실제 도메인으로 교체하여 SSL 인증서를 발급받고 Nginx 설정을 자동으로 업데이트합니다.&lt;/li&gt;
&lt;li&gt;과정 중 이메일 입력, 서비스 약관 동의, HTTPS 리디렉션 설정 등을 진행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.4 인증서 갱신 테스트&lt;/h4&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;# 인증서 갱신 테스트
sudo certbot renew --dry-run&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인증서 갱신이 정상적으로 작동하는지 테스트합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) Nginx 업스트림 설정 파일 작성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블루-그린 배포를 위해 Nginx의 업스트림 서버를 설정합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1 업스트림 설정 파일 생성&lt;/h4&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;# 업스트림 설정 디렉토리로 이동
sudo mkdir -p /etc/nginx/conf.d

# upstream.conf 파일 생성 및 편집
sudo nano /etc/nginx/conf.d/upstream.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;/etc/nginx/conf.d/&lt;/code&gt; 디렉토리에 &lt;code&gt;upstream.conf&lt;/code&gt; 파일을 생성하여 업스트림 서버 설정을 정의합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2 &lt;code&gt;upstream.conf&lt;/code&gt; 내용 복사 및 저장&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;upstream.conf&lt;/code&gt; 파일에 다음 내용을 복사하여 붙여넣습니다:&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# /etc/nginx/conf.d/upstream.conf

upstream app_servers {
    server localhost:8081; # 블루 서버 활성화
    # server localhost:8082; # 그린 서버 비활성화
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;upstream app_servers&lt;/code&gt;: Nginx가 트래픽을 전달할 서버 그룹을 정의합니다.&lt;/li&gt;
&lt;li&gt;현재는 &lt;code&gt;springboot-blue&lt;/code&gt; 서버만 활성화되어 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3 &lt;code&gt;upstream.conf&lt;/code&gt; 저장 및 종료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Nano&lt;/b&gt;에서 저장: &lt;code&gt;Ctrl + O&lt;/code&gt;, &lt;code&gt;Enter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Nano&lt;/b&gt;에서 종료: &lt;code&gt;Ctrl + X&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) Nginx 설정 파일 수정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nginx의 기본 설정 파일을 수정하여 SSL과 리버스 프록시를 설정합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1 기본 설정 파일 편집&lt;/h4&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;# 기본 설정 파일 열기
sudo nano /etc/nginx/sites-available/default&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;/etc/nginx/sites-available/default&lt;/code&gt; 파일을 열어 편집합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2 기본 설정 파일 내용 복사 및 저장&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;default&lt;/code&gt; 파일에 다음 내용을 복사하여 붙여넣습니다:&lt;/p&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;# /etc/nginx/sites-available/default

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    server_name yourdomain.com;

    # HTTP를 HTTPS로 리디렉션
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name yourdomain.com;

    # SSL 인증서 경로 설정
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # DDoS 방어 및 보안 설정
    client_body_timeout 10s;
    client_header_timeout 10s;
    client_max_body_size 1m;

    # ModSecurity 설정
    modsecurity on;
    modsecurity_rules_file /etc/nginx/modsecurity/modsecurity.conf;

    location / {
        proxy_pass http://app_servers;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # DDoS 방어 설정
        limit_req zone=ddos_limit burst=20 nodelay;
        limit_conn addr 10;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;HTTP 서버 블록&lt;/b&gt;: 모든 HTTP 요청을 HTTPS로 리디렉션합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;HTTPS 서버 블록&lt;/b&gt;: SSL 인증서를 사용하여 HTTPS 요청을 처리하고, &lt;code&gt;app_servers&lt;/code&gt; 업스트림으로 트래픽을 전달합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안 설정&lt;/b&gt;: 클라이언트 요청의 타임아웃, 최대 본문 크기 등을 설정하여 보안을 강화합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ModSecurity&lt;/b&gt;: 웹 애플리케이션 방화벽을 활성화하여 보안 위협으로부터 애플리케이션을 보호합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DDoS 방어&lt;/b&gt;: &lt;code&gt;limit_req&lt;/code&gt; 및 &lt;code&gt;limit_conn&lt;/code&gt; 지시어를 사용하여 DDoS 공격을 방어합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.3 &lt;code&gt;default&lt;/code&gt; 파일 저장 및 종료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Nano&lt;/b&gt;에서 저장: &lt;code&gt;Ctrl + O&lt;/code&gt;, &lt;code&gt;Enter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Nano&lt;/b&gt;에서 종료: &lt;code&gt;Ctrl + X&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4) Nginx 전환 스크립트 작성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블루-그린 배포 시 Nginx의 업스트림 서버를 전환하는 스크립트를 작성합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.1 스크립트 파일 생성&lt;/h4&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;# 스크립트 파일 생성
sudo nano /usr/local/bin/switch_nginx.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;/usr/local/bin/&lt;/code&gt; 디렉토리에 &lt;code&gt;switch_nginx.sh&lt;/code&gt; 스크립트 파일을 생성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.2 &lt;code&gt;switch_nginx.sh&lt;/code&gt; 내용 복사 및 저장&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;switch_nginx.sh&lt;/code&gt; 파일에 다음 내용을 복사하여 붙여넣습니다:&lt;/p&gt;
&lt;pre class=&quot;bash&quot;&gt;&lt;code&gt;#!/bin/bash

UPSTREAM_CONF=&quot;/etc/nginx/conf.d/upstream.conf&quot;
BACKUP_CONF=&quot;/etc/nginx/conf.d/upstream.conf.bak&quot;

# 현재 설정 백업
sudo cp $UPSTREAM_CONF $BACKUP_CONF

# 현재 활성화된 포트 확인
ACTIVE_PORT=$(grep -E '^\s*server localhost:808[12];' $UPSTREAM_CONF | grep -o '808[12]' | head -n1)

# 새로운 설정 생성 및 전환
if [ &quot;$ACTIVE_PORT&quot; == &quot;8081&quot; ]; then
    NEW_CONFIG=&quot;upstream app_servers {
        # server localhost:8081; # 블루 서버 비활성화
        server localhost:8082; # 그린 서버 활성화
    }&quot;
elif [ &quot;$ACTIVE_PORT&quot; == &quot;8082&quot; ]; then
    NEW_CONFIG=&quot;upstream app_servers {
        server localhost:8081; # 블루 서버 활성화
        # server localhost:8082; # 그린 서버 비활성화
    }&quot;
else
    NEW_CONFIG=&quot;upstream app_servers {
        server localhost:8081; # 블루 서버 활성화
        # server localhost:8082; # 그린 서버 비활성화
    }&quot;
fi

# 새로운 설정을 파일에 쓰기
echo &quot;$NEW_CONFIG&quot; | sudo tee $UPSTREAM_CONF

# Nginx 설정 테스트 및 적용
if sudo nginx -t; then
    sudo systemctl reload nginx
    echo &quot;Nginx 업스트림 서버 전환 성공: 활성 포트 $ACTIVE_PORT에서 전환됨.&quot;
else
    # 설정 오류 시 백업 파일 복원
    sudo cp $BACKUP_CONF $UPSTREAM_CONF
    sudo systemctl reload nginx
    echo &quot;Nginx 설정 테스트 실패: 백업 파일을 복원합니다.&quot;
    exit 1
fi&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;업스트림 설정 백업&lt;/b&gt;: 현재 Nginx 업스트림 설정을 백업합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;활성화된 포트 확인&lt;/b&gt;: 현재 활성화된 서비스 포트를 확인하여 블루 또는 그린 환경을 판단합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;새로운 설정 생성&lt;/b&gt;: 현재 활성화된 환경을 비활성화하고, 다른 환경을 활성화하는 새로운 업스트림 설정을 생성합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Nginx 재시작&lt;/b&gt;: 설정 파일을 테스트하고 문제가 없으면 Nginx를 재시작하여 변경 사항을 적용합니다. 오류가 발생하면 백업 파일을 복원합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;로그 메시지 추가&lt;/b&gt;: 성공 및 실패 시 로그 메시지를 출력하여 상태를 알립니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.3 스크립트 저장 및 종료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Nano&lt;/b&gt;에서 저장: &lt;code&gt;Ctrl + O&lt;/code&gt;, &lt;code&gt;Enter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Nano&lt;/b&gt;에서 종료: &lt;code&gt;Ctrl + X&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5) 스크립트 실행 권한 부여&lt;/h3&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;# 스크립트에 실행 권한 부여
sudo chmod +x /usr/local/bin/switch_nginx.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스크립트에 실행 권한을 부여하여 실행할 수 있게 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. Jenkins 파이프라인 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jenkins를 사용하여 CI/CD 파이프라인을 구축합니다. 이 파이프라인은 코드 변경 사항을 자동으로 빌드, 테스트, 배포하며, SonarQube를 통해 코드 품질을 분석합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) Jenkins에서 Pipeline 형식의 Item 생성&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;10.1 Jenkins 대시보드에서 새로운 Pipeline 생성&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Jenkins 웹 UI에 접속합니다. (&lt;code&gt;http://[서버 IP]:9090&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;새로운 Item&lt;/b&gt;을 클릭합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Item 이름&lt;/b&gt;을 입력합니다. 예: &lt;code&gt;moya-ci-cd-pipeline&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Pipeline&lt;/b&gt;을 선택한 후 &lt;b&gt;OK&lt;/b&gt;를 클릭합니다.&lt;br /&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1401&quot; data-origin-height=&quot;1156&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNlf3A/btsJ4dncDSu/F017GaDgj0aRFxZPIewfCk/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNlf3A/btsJ4dncDSu/F017GaDgj0aRFxZPIewfCk/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNlf3A/btsJ4dncDSu/F017GaDgj0aRFxZPIewfCk/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNlf3A%2FbtsJ4dncDSu%2FF017GaDgj0aRFxZPIewfCk%2Fimg.webp&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;1401&quot; height=&quot;1156&quot; data-origin-width=&quot;1401&quot; data-origin-height=&quot;1156&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;10.2 Pipeline 설정&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Configure&lt;/b&gt; 버튼을 클릭합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Pipeline&lt;/b&gt; 섹션으로 스크롤합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Definition&lt;/b&gt;을 &lt;code&gt;Pipeline script&lt;/code&gt;로 선택합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Pipeline Script&lt;/b&gt; 입력란에 다음 스크립트를 작성합니다.&lt;br /&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1401&quot; data-origin-height=&quot;3613&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9QD8m/btsJ3ibShE5/29rKUnn923sJ7NST1d6HS0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9QD8m/btsJ3ibShE5/29rKUnn923sJ7NST1d6HS0/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9QD8m/btsJ3ibShE5/29rKUnn923sJ7NST1d6HS0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9QD8m%2FbtsJ3ibShE5%2F29rKUnn923sJ7NST1d6HS0%2Fimg.webp&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;1401&quot; height=&quot;3613&quot; data-origin-width=&quot;1401&quot; data-origin-height=&quot;3613&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) Pipeline Script 작성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 프로젝트에 맞게 작성한 Jenkins Pipeline 스크립트입니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;pipeline {
    agent any

    tools {
        maven 'Maven'
    }

    environment {
        MAVEN_HOME = tool 'Maven'
        PATH = &quot;${MAVEN_HOME}/bin:${env.PATH}&quot;
        DOCKER_IMAGE = 'your_dockerhub_username/moya:latest'
        SSH_CREDENTIALS = 'ssh-key-id'
        SERVER_IP = 'yourdomain.com'
        SSH_USER = 'ubuntu'
    }

    stages {
        stage('Git Checkout') {
            steps {
                script {
                    echo &quot;=== Git 레포지토리 체크아웃 중 ===&quot;
                    checkout([$class: 'GitSCM', branches: [[name: '*/develop']], 
                              userRemoteConfigs: [[url: 'https://lab.ssafy.com/s11-ai-image-sub1/S11P21D202.git', 
                                                  credentialsId: 'gitlab']]])
                    sh 'ls -la'
                }
            }
        }

        stage('Set Permissions') {
            steps {
                echo &quot;=== 파일 권한 설정 중 ===&quot;
                sh 'chmod -R 777 backend'
            }
        }

        stage('Copy Secret Files') {
            steps {
                script {
                    echo &quot;=== 시크릿 파일을 복사 중 ===&quot;
                    withCredentials([file(credentialsId: 'env', variable: 'ENV_FILE'),
                                     file(credentialsId: 'application.properties', variable: 'APP_PROPERTIES'),
                                     file(credentialsId: 'application-oauth-kakao.properties', variable: 'OAUTH_PROPERTIES')]) {
                        sh 'cp $ENV_FILE backend/.env'
                        sh 'cp $APP_PROPERTIES backend/src/main/resources/application.properties'
                        sh 'cp $OAUTH_PROPERTIES backend/src/main/resources/application-oauth-kakao.properties'
                    }
                }
            }
        }

        stage('Maven Compile') {
            steps {
                dir('backend') {
                    script {
                        echo &quot;=== Maven Compile ===&quot;
                        if (fileExists('pom.xml')) {
                            sh 'mvn clean compile'
                        } else {
                            error 'pom.xml 파일이 존재하지 않습니다.'
                        }
                    }
                }
            }
        }

        stage('Maven Package') {
            steps {
                dir('backend') {
                    echo &quot;=== Maven 패키징 중 ===&quot;
                    sh 'mvn package -DskipTests'
                }
            }
        }

        stage('Docker Build and Push') {
            steps {
                dir('backend') {
                    script {
                        echo &quot;=== Docker 이미지 빌드 중 ===&quot;
                        sh 'docker build -t your_dockerhub_username/moya:latest .'

                        echo &quot;=== DockerHub로 이미지 푸시 중 ===&quot;
                        withCredentials([usernamePassword(credentialsId: 'docker-credentials-id', passwordVariable: 'DOCKER_HUB_PASSWORD', usernameVariable: 'DOCKER_HUB_USERNAME')]) {
                            sh 'echo $DOCKER_HUB_PASSWORD | docker login -u $DOCKER_HUB_USERNAME --password-stdin'
                            sh 'docker push your_dockerhub_username/moya:latest'
                        }
                    }
                }
            }
        }

        stage('Deploy to Inactive Environment') {
            steps {
                script {
                    echo &quot;=== 비활성화된 환경에 배포 중 ===&quot;
                    sshagent([SSH_CREDENTIALS]) {
                        sh '''
                            ACTIVE_PORT=$(ssh -o StrictHostKeyChecking=no ${SSH_USER}@${SERVER_IP} &quot;sudo grep -E '^\\s*server localhost:808[12];' /etc/nginx/conf.d/upstream.conf | grep -o '808[12]' | head -n1&quot;)
                            echo 현재 활성 환경 포트: ${ACTIVE_PORT}

                            if [ &quot;${ACTIVE_PORT}&quot; = &quot;8081&quot; ]; then
                                INACTIVE_SERVICE=&quot;springboot-green&quot;
                                IMAGE_TAG=&quot;green&quot;
                                INACTIVE_PORT=&quot;8082&quot;
                                echo &quot;비활성 환경: 그린 (포트 8082)&quot;
                            elif [ &quot;${ACTIVE_PORT}&quot; = &quot;8082&quot; ]; then
                                INACTIVE_SERVICE=&quot;springboot-blue&quot;
                                IMAGE_TAG=&quot;blue&quot;
                                INACTIVE_PORT=&quot;8081&quot;
                                echo &quot;비활성 환경: 블루 (포트 8081)&quot;
                            else
                                INACTIVE_SERVICE=&quot;springboot-blue&quot;
                                IMAGE_TAG=&quot;blue&quot;
                                INACTIVE_PORT=&quot;8081&quot;
                            fi

                            ssh -o StrictHostKeyChecking=no ${SSH_USER}@${SERVER_IP} &quot;docker-compose -f /home/ubuntu/moya/backend/docker-compose.yml stop ${INACTIVE_SERVICE} &amp;amp;&amp;amp; docker-compose -f /home/ubuntu/moya/backend/docker-compose.yml rm -f ${INACTIVE_SERVICE}&quot;
                            ssh -o StrictHostKeyChecking=no ${SSH_USER}@${SERVER_IP} &quot;docker pull your_dockerhub_username/moya:latest &amp;amp;&amp;amp; docker tag your_dockerhub_username/moya:latest your_dockerhub_username/moya:${IMAGE_TAG} &amp;amp;&amp;amp; cd /home/ubuntu/moya/backend &amp;amp;&amp;amp; docker-compose -f /home/ubuntu/moya/backend/docker-compose.yml up -d --no-deps ${INACTIVE_SERVICE}&quot;
                            ssh -o StrictHostKeyChecking=no ${SSH_USER}@${SERVER_IP} &quot;docker-compose -f /home/ubuntu/moya/backend/docker-compose.yml ps ${INACTIVE_SERVICE}&quot;
                        '''
                    }
                }
            }
        }

        stage('Wait for Stabilization') {
            steps {
                echo &quot;=== 새로운 컨테이너 안정화 대기 중 ===&quot;
                sleep time: 10, unit: 'SECONDS'
            }
        }

        stage('Health Check') {
            steps {
                script {
                    echo &quot;=== 헬스 체크 수행 중 ===&quot;
                    sshagent([SSH_CREDENTIALS]) {
                        sh '''
                            set +e
                            MAX_RETRIES=12
                            RETRY_INTERVAL=5

                            ACTIVE_PORT=$(ssh -o StrictHostKeyChecking=no ${SSH_USER}@${SERVER_IP} &quot;sudo grep -E '^\\s*server localhost:808[12];' /etc/nginx/conf.d/upstream.conf | grep -o '808[12]' | head -n1&quot;)
                            if [ &quot;${ACTIVE_PORT}&quot; = &quot;8081&quot; ]; then
                                INACTIVE_PORT=&quot;8082&quot;
                            else
                                INACTIVE_PORT=&quot;8081&quot;
                            fi

                            HEALTH_CHECK_URL=&quot;http://${SERVER_IP}:${INACTIVE_PORT}/health&quot;
                            echo &quot;헬스 체크 URL: ${HEALTH_CHECK_URL}&quot;

                            RETRIES=0

                            while [ $RETRIES -lt $MAX_RETRIES ]; do
                                STATUS=$(curl -s -o /dev/null -w '%{http_code}' ${HEALTH_CHECK_URL})
                                if [ &quot;$STATUS&quot; -eq 200 ]; then
                                    echo &quot;헬스 체크 성공!&quot;
                                    exit 0
                                else
                                    echo &quot;헬스 체크 실패, ${RETRY_INTERVAL}초 후 재시도... (${RETRIES}/${MAX_RETRIES})&quot;
                                    RETRIES=$((RETRIES+1))
                                    sleep $RETRY_INTERVAL
                                fi
                            done
                            echo &quot;헬스 체크 실패: 최대 재시도 횟수 초과&quot;
                            exit 1
                        '''
                    }
                }
            }
        }

        stage('Switch Nginx to New Environment') {
            steps {
                script {
                    echo &quot;=== Nginx를 새로운 환경으로 전환 중 ===&quot;
                    sshagent([SSH_CREDENTIALS]) {
                        sh '''
                            ssh -T -o StrictHostKeyChecking=no ${SSH_USER}@${SERVER_IP} &amp;lt;&amp;lt; EOF
                                echo &quot;현재 Nginx 설정:&quot;
                                sudo cat /etc/nginx/conf.d/upstream.conf
                                echo &quot;스크립트 실행 중...&quot;
                                sudo bash /usr/local/bin/switch_nginx.sh
                                echo &quot;스크립트 실행 완료&quot;
                                echo &quot;변경 후 Nginx 설정:&quot;
                                sudo cat /etc/nginx/conf.d/upstream.conf
                                echo &quot;Nginx 상태 확인:&quot;
                                sudo systemctl --no-pager status nginx
                                exit
                            EOF
                        '''
                    }
                }
            }
        }

        stage('SonarQube Analysis') {
            steps {
                dir('backend') {
                    script {
                        echo &quot;=== SonarQube 분석 중 ===&quot;
                        withSonarQubeEnv('moya') {
                            withCredentials([string(credentialsId: 'sonarQubeToken', variable: 'SONAR_TOKEN')]) {
                                sh 'mvn sonar:sonar -Dsonar.projectKey=com.e22e:moya -Dsonar.host.url=http://yourdomain.com:9000 -Dsonar.login=$SONAR_TOKEN'
                            }
                        }
                    }
                }
            }
        }

        stage('Notify Mattermost') {
            steps {
                script {
                    echo &quot;=== Mattermost에 알림 전송 중 ===&quot;
                    mattermostSend color: '#32a852', message: &quot;&quot;&quot;빌드 성공 (${env.JOB_NAME}) #(${env.BUILD_NUMBER}) (&amp;lt;${env.BUILD_URL}|Open&amp;gt;)
See the (&amp;lt;${env.BUILD_URL}console|console&amp;gt;)&quot;&quot;&quot;
                }
            }
        }
    }

    post {
        always {
            script {
                echo &quot;=== Cleanup 또는 에러 처리 중 ===&quot;
            }
        }

        failure {
            script {
                echo &quot;=== 빌드 실패, 알림 전송 ===&quot;
                mattermostSend color: '#ff0000', message: &quot;&quot;&quot;빌드 실패 (${env.JOB_NAME}) #(${env.BUILD_NUMBER}) (&amp;lt;${env.BUILD_URL}|Open&amp;gt;)
See the (&amp;lt;${env.BUILD_URL}console|console&amp;gt;)&quot;&quot;&quot;
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Environment Variables&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;MAVEN_HOME&lt;/code&gt;, &lt;code&gt;PATH&lt;/code&gt;: Maven 빌드 도구의 경로 설정.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DOCKER_IMAGE&lt;/code&gt;: Docker Hub에 푸시할 이미지 이름.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SSH_CREDENTIALS&lt;/code&gt;: Jenkins에 등록한 SSH 자격 증명 ID.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SERVER_IP&lt;/code&gt;, &lt;code&gt;SSH_USER&lt;/code&gt;: 배포 대상 서버의 IP와 사용자 이름.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Stages&lt;/b&gt;:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Git Checkout&lt;/b&gt;: GitLab 저장소에서 코드를 클론하여 빌드를 준비합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Set Permissions&lt;/b&gt;: &lt;code&gt;backend&lt;/code&gt; 디렉토리의 파일 권한을 설정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Copy Secret Files&lt;/b&gt;: 시크릿 파일(.env, Spring 설정 파일 등)을 &lt;code&gt;backend&lt;/code&gt; 디렉토리에 복사하여 애플리케이션이 올바르게 설정되도록 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Maven Compile&lt;/b&gt;: Maven을 사용하여 프로젝트를 컴파일합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Maven Package&lt;/b&gt;: Maven을 사용하여 프로젝트를 패키징합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Docker Build and Push&lt;/b&gt;: Docker 이미지를 빌드하고 Docker Hub에 푸시합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Deploy to Inactive Environment&lt;/b&gt;: 블루-그린 배포 전략에 따라 비활성화된 환경에 새 버전을 배포합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Wait for Stabilization&lt;/b&gt;: 새로운 컨테이너의 안정화를 위해 잠시 대기합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Health Check&lt;/b&gt;: 배포된 애플리케이션의 상태를 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Switch Nginx to New Environment&lt;/b&gt;: Nginx 설정을 변경하여 트래픽을 새로운 버전으로 전환합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SonarQube Analysis&lt;/b&gt;: SonarQube를 사용하여 코드 품질을 분석합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Notify Mattermost&lt;/b&gt;: 빌드 및 배포 결과를 팀 커뮤니케이션 도구인 Mattermost에 알림으로 전송합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Post Actions&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;always&lt;/b&gt;: 모든 빌드 후에 수행되는 단계입니다. (예: Cleanup)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;failure&lt;/b&gt;: 빌드 실패 시 Mattermost에 실패 알림을 전송합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;10.3 &lt;code&gt;Jenkinsfile&lt;/code&gt; 저장 및 종료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Nano&lt;/b&gt;에서 저장: &lt;code&gt;Ctrl + O&lt;/code&gt;, &lt;code&gt;Enter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Nano&lt;/b&gt;에서 종료: &lt;code&gt;Ctrl + X&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) 파이프라인 설명&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Git Checkout&lt;/b&gt;: GitLab에서 소스 코드를 클론하여 빌드를 준비합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Set Permissions&lt;/b&gt;: 빌드와 배포에 필요한 파일 권한을 설정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Copy Secret Files&lt;/b&gt;: 시크릿 파일(.env, Spring 설정 파일 등)을 &lt;code&gt;backend&lt;/code&gt; 디렉토리에 복사하여 애플리케이션이 올바르게 설정되도록 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Maven Compile&lt;/b&gt;: Maven을 사용하여 프로젝트를 컴파일합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Maven Package&lt;/b&gt;: Maven을 사용하여 프로젝트를 패키징합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Docker Build and Push&lt;/b&gt;: Docker 이미지를 빌드하고, Docker Hub에 푸시하여 배포를 준비합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Deploy to Inactive Environment&lt;/b&gt;: 블루-그린 배포 전략에 따라 비활성화된 환경에 새로운 버전을 배포합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Wait for Stabilization&lt;/b&gt;: 배포된 애플리케이션의 안정화를 위해 잠시 대기합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Health Check&lt;/b&gt;: 애플리케이션의 상태를 확인하여 정상적으로 동작하는지 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Switch Nginx to New Environment&lt;/b&gt;: Nginx 설정을 변경하여 트래픽을 새로운 버전으로 전환합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SonarQube Analysis&lt;/b&gt;: SonarQube를 사용하여 코드의 버그, 보안 취약점, 코드 스멜 등을 분석하여 코드 품질을 관리합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Notify Mattermost&lt;/b&gt;: 빌드 및 배포 결과를 팀 커뮤니케이션 도구인 Mattermost에 알림으로 전송합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;11. SonarQube를 통한 코드 품질 관리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SonarQube&lt;/b&gt;는 소스 코드의 품질을 자동으로 분석하고, 코드의 버그, 보안 취약점, 코드 스멜 등을 감지하여 개선할 수 있는 도구입니다. 이를 통해 지속적으로 코드 품질을 유지하고 향상시킬 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) SonarQube 설치 및 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SonarQube를 Docker 컨테이너로 설치합니다.&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;# SonarQube Docker 컨테이너 실행
docker run -d \
  --name sonarqube \
  -e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true \
  -p 9000:9000 \
  sonarqube:latest&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;-e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true&lt;/code&gt;: Elasticsearch 관련 초기 체크를 비활성화하여 메모리 부족 문제를 방지합니다. (실제 환경에서는 적절한 메모리 할당을 권장)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p 9000:9000&lt;/code&gt;: SonarQube UI에 접근하기 위한 포트를 매핑합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;SonarQube 컨테이너 상태 확인&lt;/h4&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;docker ps&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;출력 결과 예시&lt;/b&gt;:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;CONTAINER ID   IMAGE            COMMAND                  CREATED        STATUS        PORTS                     NAMES
7f31b90ff248   sonarqube:latest &quot;/opt/sonarqube/dock&amp;hellip;&quot;   2 weeks ago    Up 2 weeks    0.0.0.0:9000-&amp;gt;9000/tcp    sonarqube&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) SonarQube 초기 설정&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;브라우저에서 &lt;code&gt;http://yourdomain.com:9000&lt;/code&gt;에 접속합니다.&lt;/li&gt;
&lt;li&gt;기본 계정(&lt;code&gt;admin&lt;/code&gt;/&lt;code&gt;admin&lt;/code&gt;)으로 로그인합니다.&lt;/li&gt;
&lt;li&gt;보안을 위해 비밀번호를 변경합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;My Account &amp;gt; Security&lt;/b&gt; 탭에서 &lt;b&gt;Token&lt;/b&gt;을 생성합니다. 이 토큰은 Jenkins와 연동할 때 사용됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) Jenkins에 SonarQube 연동&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Jenkins 관리 페이지&lt;/b&gt;로 이동합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Manage Jenkins &amp;gt; Configure System&lt;/b&gt;으로 들어갑니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SonarQube servers&lt;/b&gt; 섹션에서 &lt;b&gt;Add SonarQube&lt;/b&gt;를 클릭합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Name&lt;/b&gt;: SonarQube&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Server URL&lt;/b&gt;: &lt;code&gt;http://yourdomain.com:9000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Server authentication token&lt;/b&gt;: Jenkins의 Credentials에 저장한 SonarQube 토큰을 선택합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Save&lt;/b&gt;를 클릭하여 설정을 저장합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4) Jenkins Pipeline에서 SonarQube 분석 단계 추가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 작성한 Jenkins Pipeline 스크립트에 &lt;b&gt;SonarQube Analysis&lt;/b&gt; 단계가 포함되어 있습니다. 이를 통해 빌드 과정 중에 코드 품질을 자동으로 분석할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;stage('SonarQube Analysis') {
    steps {
        dir('backend') {
            script {
                echo &quot;=== SonarQube 분석 중 ===&quot;
                withSonarQubeEnv('moya') {
                    withCredentials([string(credentialsId: 'sonarQubeToken', variable: 'SONAR_TOKEN')]) {
                        sh 'mvn sonar:sonar -Dsonar.projectKey=com.e22e:moya -Dsonar.host.url=http://yourdomain.com:9000 -Dsonar.login=$SONAR_TOKEN'
                    }
                }
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;withSonarQubeEnv&lt;/code&gt;: SonarQube 서버와의 연동 환경을 설정합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;withCredentials&lt;/code&gt;: SonarQube 토큰을 안전하게 Jenkins 파이프라인에 주입합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mvn sonar:sonar&lt;/code&gt;: Maven을 사용하여 SonarQube 분석을 실행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SonarQube 분석 결과&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Jenkins 빌드가 완료된 후, SonarQube 웹 UI에서 코드 품질 보고서를 확인할 수 있습니다.&lt;/li&gt;
&lt;li&gt;Jenkins의 콘솔 로그에서도 SonarQube 분석 진행 상황과 결과를 확인할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12. 보안 강화 설정 (Fail2Ban 및 ModSecurity)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버의 보안을 강화하기 위해 &lt;b&gt;Fail2Ban&lt;/b&gt;과 &lt;b&gt;ModSecurity&lt;/b&gt;를 설치하고 설정합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) Fail2Ban 설치 및 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Fail2Ban&lt;/b&gt;은 악의적인 IP 주소로부터 서버를 보호하는 데 사용됩니다. 주로 SSH 로그인 시도, DDoS 공격 등을 방어합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1 Fail2Ban 설치&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# Fail2Ban 설치
sudo apt-get update
sudo apt-get install fail2ban -y&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;sudo apt-get install fail2ban -y&lt;/code&gt;: Fail2Ban을 설치합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2 설정 파일 생성 및 수정&lt;/h4&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;# jail.local 파일 생성 및 편집
sudo nano /etc/fail2ban/jail.local&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;jail.local&lt;/code&gt;: Fail2Ban의 규칙을 정의하는 파일입니다. 사용자 정의 규칙을 추가할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3 &lt;code&gt;jail.local&lt;/code&gt; 파일에 다음 내용 추가&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;[nginx-req-limit]
enabled = true
filter = nginx-req-limit
action = iptables-multiport[name=ReqLimit, port=&quot;http,https&quot;, protocol=tcp]
logpath = /var/log/nginx/error.log
findtime = 600
bantime = 7200
maxretry = 10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;[nginx-req-limit]&lt;/b&gt;: Nginx의 요청 제한을 모니터링하는 Fail2Ban 규칙입니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;enabled = true&lt;/code&gt;: 이 규칙을 활성화합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;filter = nginx-req-limit&lt;/code&gt;: 사용할 필터 이름입니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;action = iptables-multiport[name=ReqLimit, port=&quot;http,https&quot;, protocol=tcp]&lt;/code&gt;: 차단 시 사용할 액션을 정의합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;logpath = /var/log/nginx/error.log&lt;/code&gt;: 로그 파일 경로를 지정합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;findtime = 600&lt;/code&gt;: 10분 동안 시도 횟수를 셉니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bantime = 7200&lt;/code&gt;: 2시간 동안 IP를 차단합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maxretry = 10&lt;/code&gt;: 최대 시도 횟수입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.4 필터 설정 파일 생성&lt;/h4&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;sudo nano /etc/fail2ban/filter.d/nginx-req-limit.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;nginx-req-limit.conf&lt;/code&gt;: Nginx의 요청 제한 로그 패턴을 정의하는 Fail2Ban 필터 파일입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.5 &lt;code&gt;nginx-req-limit.conf&lt;/code&gt; 파일에 다음 내용 추가&lt;/h4&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;[Definition]
failregex = limiting requests, excess:.* by zone&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;failregex&lt;/b&gt;: 로그 파일에서 Fail2Ban이 차단할 패턴을 정의합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.6 Fail2Ban 재시작 및 상태 확인&lt;/h4&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# Fail2Ban 재시작
sudo systemctl restart fail2ban

# Fail2Ban 상태 확인
sudo fail2ban-client status
sudo fail2ban-client status nginx-req-limit&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;sudo systemctl restart fail2ban&lt;/code&gt;: Fail2Ban 서비스를 재시작하여 설정을 적용합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo fail2ban-client status&lt;/code&gt;: Fail2Ban의 전반적인 상태를 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo fail2ban-client status nginx-req-limit&lt;/code&gt;: 특정 jails의 상태를 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) ModSecurity 웹 방화벽 설치 및 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ModSecurity&lt;/b&gt;는 웹 애플리케이션 방화벽으로, 악의적인 요청을 필터링하여 서버를 보호합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1 ModSecurity 및 OWASP CRS 설치&lt;/h4&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;# ModSecurity 및 OWASP CRS 설치
sudo apt-get update
sudo apt-get install -y libnginx-mod-security
sudo apt-get install -y modsecurity-crs&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;libnginx-mod-security&lt;/code&gt;: Nginx용 ModSecurity 모듈을 설치합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;modsecurity-crs&lt;/code&gt;: OWASP Core Rule Set을 설치하여 기본 보안 규칙을 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2 ModSecurity 설정 파일 수정&lt;/h4&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;sudo nano /etc/nginx/modsecurity/modsecurity.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;modsecurity.conf&lt;/code&gt;: ModSecurity의 주요 설정 파일입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3 &lt;code&gt;modsecurity.conf&lt;/code&gt; 파일에 다음 내용 추가&lt;/h4&gt;
&lt;pre class=&quot;apache&quot;&gt;&lt;code&gt;SecRuleEngine On&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;SecRuleEngine On&lt;/code&gt;: ModSecurity를 활성화합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.4 OWASP CRS 설정 파일 복사 및 링크 생성&lt;/h4&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;# CRS 설정 파일 복사
sudo cp /usr/share/modsecurity-crs/crs-setup.conf.example /etc/nginx/modsecurity/crs-setup.conf

# CRS 규칙 파일 링크 생성
sudo ln -s /usr/share/modsecurity-crs/rules /etc/nginx/modsecurity/rules&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;crs-setup.conf.example&lt;/code&gt;: OWASP CRS의 기본 설정 파일입니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/usr/share/modsecurity-crs/rules&lt;/code&gt;: CRS 규칙 파일들이 위치한 디렉토리입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.5 ModSecurity 설정 파일에 CRS 포함&lt;/h4&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;echo 'Include /etc/nginx/modsecurity/crs-setup.conf' | sudo tee -a /etc/nginx/modsecurity/modsecurity.conf
echo 'Include /etc/nginx/modsecurity/rules/*.conf' | sudo tee -a /etc/nginx/modsecurity/modsecurity.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;Include&lt;/code&gt; 지시어를 사용하여 CRS 설정과 규칙 파일들을 ModSecurity 설정에 포함시킵니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.6 Nginx 설정 테스트 및 재시작&lt;/h4&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# Nginx 설정 테스트
sudo nginx -t

# Nginx 재시작
sudo systemctl reload nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;sudo nginx -t&lt;/code&gt;: Nginx 설정 파일의 문법을 검사합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo systemctl reload nginx&lt;/code&gt;: 설정 파일을 재적용하여 변경 사항을 반영합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13. 마무리 및 개선 사항&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결과&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;무중단 배포 구현 성공&lt;/b&gt;: 블루-그린 배포 방식을 통해 서비스 중단 없이 새로운 버전을 배포할 수 있게 되었습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자동화된 배포 프로세스 구축&lt;/b&gt;: CI/CD 파이프라인을 통해 배포 과정이 자동화되어 배포 시간과 인적 오류를 줄일 수 있었습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;코드 품질 관리 강화&lt;/b&gt;: SonarQube를 통해 지속적인 코드 품질 관리를 할 수 있게 되었습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안 강화&lt;/b&gt;: Fail2Ban과 ModSecurity를 적용하여 서버 보안을 강화하였습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DockerHub 활용&lt;/b&gt;: DockerHub를 통해 Docker 이미지를 효과적으로 관리하고 배포할 수 있게 되었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개선 사항&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;자동 롤백 기능 도입&lt;/b&gt;: 배포 실패 시 자동으로 이전 버전으로 롤백하는 기능을 추가하여 배포 안정성을 높일 계획입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모니터링 도구 도입&lt;/b&gt;: Prometheus와 Grafana 등을 도입하여 시스템 및 애플리케이션 모니터링을 강화할 예정입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CI/CD 파이프라인 최적화&lt;/b&gt;: 빌드 시간 단축 및 효율적인 리소스 사용을 위한 최적화를 진행할 예정입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;헬스 체크 강화&lt;/b&gt;: 애플리케이션의 상태를 더욱 정확하게 확인하기 위해 다양한 헬스 체크 방법을 도입할 계획입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DockerHub 보안 강화&lt;/b&gt;: DockerHub 저장소의 접근 권한을 세분화하고, 보안 설정을 강화하여 이미지 보안을 높일 예정입니다.&lt;/li&gt;
&lt;/ul&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;b&gt;CI/CD&lt;/b&gt;를 통해 &lt;b&gt;블루-그린 배포&lt;/b&gt; 방식을 적용하여 &lt;b&gt;무중단 배포&lt;/b&gt;를 구현하는 과정을 상세히 설명하였습니다. &lt;b&gt;CI/CD&lt;/b&gt;를 처음 접하시는 분들도 따라 할 수 있도록 각 단계별 명령어와 설정 파일 생성 및 수정 방법을 최대한 상세히 포함하였으며, 필요한 개념에 대한 설명도 함께 제공하였습니다. 또한, DockerHub의 활용 방법과 그 중요성에 대해 추가로 설명하였습니다. 이 글이 여러분의 프로젝트에 도움이 되었기를 바랍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;추가 팁 및 참고 자료&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;파일 편집기 사용법&lt;/b&gt;: 본 가이드에서는 &lt;code&gt;nano&lt;/code&gt; 편집기를 사용하였으나, 다른 편집기(&lt;code&gt;vi&lt;/code&gt;, &lt;code&gt;vim&lt;/code&gt;, &lt;code&gt;emacs&lt;/code&gt; 등)를 사용할 수도 있습니다. 각 편집기의 기본 사용법을 익히면 더욱 편리하게 파일을 수정할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Jenkins 플러그인 설치&lt;/b&gt;: Jenkins에서 다양한 기능을 활용하기 위해 필요한 플러그인들을 사전에 설치해두면 파이프라인 설정이 용이합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안 키 관리&lt;/b&gt;: SSH 키, API 토큰 등 민감한 정보는 Jenkins의 Credentials 관리 기능을 통해 안전하게 관리해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;로그 모니터링&lt;/b&gt;: 배포 및 운영 중 발생하는 문제를 신속하게 파악하기 위해 로그 파일을 지속적으로 모니터링하는 습관을 들이세요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;백업 전략&lt;/b&gt;: 중요한 데이터와 설정 파일에 대한 정기적인 백업을 통해 예상치 못한 문제 발생 시 신속하게 복구할 수 있도록 준비하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외에도 다양한 자료와 튜토리얼이 온라인에 많이 있으니, 필요에 따라 추가적으로 학습하시기를 권장드립니다.&lt;/p&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;b&gt;참고 자료&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/&quot;&gt;Docker 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jenkins.io/doc/&quot;&gt;Jenkins 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.sonarqube.org/latest/&quot;&gt;SonarQube 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.fail2ban.org/wiki/index.php/Main_Page&quot;&gt;Fail2Ban 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.modsecurity.org/&quot;&gt;ModSecurity 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hub.docker.com/&quot;&gt;DockerHub 공식 사이트&lt;/a&gt;&lt;/li&gt;
&lt;/ul&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;b&gt;주의 사항&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제 운영 환경에서는 보안 설정을 더욱 강화하고, 비밀번호와 API 키는 절대로 공개하지 않도록 주의하세요.&lt;/li&gt;
&lt;li&gt;본 가이드는 기본적인 설정을 다루고 있으며, 실제 프로젝트의 요구 사항에 따라 추가적인 설정이 필요할 수 있습니다.&lt;/li&gt;
&lt;/ul&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;이제 CI/CD 파이프라인과 블루-그린 배포 방식을 통해 효율적이고 안정적인 애플리케이션 배포를 경험해보세요!&lt;/p&gt;</description>
      <category>DevOps</category>
      <category>CI/CD</category>
      <category>DevOps</category>
      <category>docker</category>
      <category>fail2ban</category>
      <category>Jenkins</category>
      <category>modsecurity</category>
      <category>nginx</category>
      <category>sonarqube</category>
      <category>무중단 배포</category>
      <category>블루 그린 배포</category>
      <author>422haha</author>
      <guid isPermaLink="true">https://dev-miyeon.tistory.com/1</guid>
      <comments>https://dev-miyeon.tistory.com/1#entry1comment</comments>
      <pubDate>Sun, 13 Oct 2024 22:47:17 +0900</pubDate>
    </item>
  </channel>
</rss>