<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>꾸준히 공부중</title>
    <link>https://seriouskang.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 18 Aug 2026 03:40:15 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>시리어스강</managingEditor>
    <item>
      <title>[haproxy] 클라이언트 IP 유지하기</title>
      <link>https://seriouskang.tistory.com/18</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스에 배포한 워크로드에 대한 접근을 사내 L4 장비에 연계하여 하고 있는데, 사내에서 제공되는 L4 장비의 기능에 미흡한 부분도 있고&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;(ex. 요청 실패 시 retry, redispatch 불가)&lt;/i&gt;&lt;/span&gt; L4 장비에 대한 조작 권한이 없어 로드 밸런서 대상 그룹 변경이 필요할 때&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;(ex. 클러스터 업그레이드)&lt;/i&gt;&lt;/span&gt; 인프라팀의 지원을 기다려야 하는 상황을 벗어나기 위해 haproxy를 통해 리버스 프록싱을 하는 방안을 마련 중에 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 haproxy를 도입하면서 클라이언트의 IP가 haproxy의 주소로 덮어써지는 문제가 있어서, 이를 해결하기 위한 방안을 공부하며 겸사겸사 포스팅도 해보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dI8MgT/btsPC8N7Nmd/j4kTaXfxGGDVZuqRPPyCAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dI8MgT/btsPC8N7Nmd/j4kTaXfxGGDVZuqRPPyCAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dI8MgT/btsPC8N7Nmd/j4kTaXfxGGDVZuqRPPyCAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdI8MgT%2FbtsPC8N7Nmd%2Fj4kTaXfxGGDVZuqRPPyCAk%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;500&quot; height=&quot;375&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;클라이언트 IP 변조 확인&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;테스트&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테스트를 위한 트래픽 흐름: client&amp;nbsp;&amp;rarr; haproxy &amp;rarr; apache &amp;rarr; application
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;apache 대신 k8s ingress나 istio 등으로 테스트하는게 실제 서비스 환경과 비슷했겠지만, 배보다 배꼽이 더 커질 것 같아서 비교적 간단하게 구성을 했다.&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;sample&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;haproxy.cfg&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1753788738545&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;frontend main
        bind *:80
        default_backend app
        mode tcp

backend app
        # apache
        server app1 192.168.64.148:80 check
        mode http&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;haproxy &amp;rarr; apache 호출 시, X-Forwarded-For(XFF) 헤더는 포함되지 않은 것을 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;1364&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IooSs/btsPBf80vfW/KqqTfpAFXQrK4p92ik9hr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IooSs/btsPBf80vfW/KqqTfpAFXQrK4p92ik9hr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IooSs/btsPBf80vfW/KqqTfpAFXQrK4p92ik9hr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIooSs%2FbtsPBf80vfW%2FKqqTfpAFXQrK4p92ik9hr1%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;1364&quot; height=&quot;494&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;1364&quot; data-origin-height=&quot;494&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;apache &amp;rarr; application 호출 시, XFF 헤더에 haproxy의 주소가 세팅. 이로 인해 어플리케이션은 haproxy IP를 클라이언트 IP로 착각하는 상황 발생할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;1372&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbHTgn/btsPC6CSLmo/0cSI1ZDhwBbfktuTStHDtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbHTgn/btsPC6CSLmo/0cSI1ZDhwBbfktuTStHDtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbHTgn/btsPC6CSLmo/0cSI1ZDhwBbfktuTStHDtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbHTgn%2FbtsPC6CSLmo%2F0cSI1ZDhwBbfktuTStHDtk%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;1372&quot; height=&quot;600&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;1372&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;방안 1. XFF header&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트가 요청을 보낼 때, 클라이언트 주소를 XFF 헤더에 저장하여 HTTP 메세지를 릴레이&lt;/li&gt;
&lt;li&gt;클라이언트의 HTTP API 호출 방식을 변경해야되므로, 실효성이 있을진 의문&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;sample&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트 측에서 API 호출 시, XFF 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1753789065553&quot; class=&quot;x86asm&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# XFF 헤더에 클라이언트 IP 세팅
$ curl -H &quot;X-Forwarded-For: 192.168.64.146&quot; ubuntu.test.cluster/client-ip&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;haproxy&amp;nbsp;&amp;rarr;&amp;nbsp;apache&amp;nbsp;호출&amp;nbsp;시,&amp;nbsp;XFF&amp;nbsp;헤더에&amp;nbsp;클라이언트&amp;nbsp;IP가&amp;nbsp;세팅&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;1356&quot; data-origin-height=&quot;498&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lXlde/btsPCRFU6Ja/jREzB43kp8evqZKz1MnmoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lXlde/btsPCRFU6Ja/jREzB43kp8evqZKz1MnmoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lXlde/btsPCRFU6Ja/jREzB43kp8evqZKz1MnmoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlXlde%2FbtsPCRFU6Ja%2FjREzB43kp8evqZKz1MnmoK%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;1356&quot; height=&quot;498&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;1356&quot; data-origin-height=&quot;498&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;apache &amp;rarr; application 호출 시, apache 설정에 따라 XFF 헤더에 클라이언트 IP와 haproxy의 IP가 세팅&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;1358&quot; data-origin-height=&quot;586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wBFqI/btsPDPN7SEs/WqeOkeN5h4n0lEkDPyPav0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wBFqI/btsPDPN7SEs/WqeOkeN5h4n0lEkDPyPav0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wBFqI/btsPDPN7SEs/WqeOkeN5h4n0lEkDPyPav0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwBFqI%2FbtsPDPN7SEs%2FWqeOkeN5h4n0lEkDPyPav0%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;1358&quot; height=&quot;586&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;1358&quot; data-origin-height=&quot;586&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;방안&amp;nbsp;2.&amp;nbsp;haproxy&amp;nbsp;forwardfor&amp;nbsp;option&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;haproxy option forwarfor 사용 시, haproxy가 클라이언트 IP를 XFF 헤더에 삽입&lt;/li&gt;
&lt;li&gt;HTTP 헤더를 추가하는 방식이므로, HTTP 모드에서 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;sample&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;haproxy.cfg&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1753789353025&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;frontend main
    bind *:80
    default_backend app
    mode tcp

backend app
    option forwardfor ✅
    mode http&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;haproxy &amp;rarr; apache 시, XFF 헤더에 클라이언트 IP가 세팅
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트에서 XFF 헤더를 추가할 필요가 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;1358&quot; data-origin-height=&quot;488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3F40N/btsPCIhXKJD/c4evPOBP8k3oGqKB814zO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3F40N/btsPCIhXKJD/c4evPOBP8k3oGqKB814zO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3F40N/btsPCIhXKJD/c4evPOBP8k3oGqKB814zO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3F40N%2FbtsPCIhXKJD%2Fc4evPOBP8k3oGqKB814zO0%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;1358&quot; height=&quot;488&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;1358&quot; data-origin-height=&quot;488&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;apache&amp;nbsp;&amp;rarr;&amp;nbsp;application&amp;nbsp;시,&amp;nbsp;XFF&amp;nbsp;헤더에&amp;nbsp;클라이언트&amp;nbsp;IP와&amp;nbsp;haproxy의&amp;nbsp;IP가&amp;nbsp;세팅&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;1362&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpqoKm/btsPC5xcadT/bT4tWbUcUMWdwyvhodg4A0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpqoKm/btsPC5xcadT/bT4tWbUcUMWdwyvhodg4A0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpqoKm/btsPC5xcadT/bT4tWbUcUMWdwyvhodg4A0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpqoKm%2FbtsPC5xcadT%2FbT4tWbUcUMWdwyvhodg4A0%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;1362&quot; height=&quot;598&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;1362&quot; data-origin-height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;방안&amp;nbsp;3.&amp;nbsp;haproxy&amp;nbsp;forwarded&amp;nbsp;option&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;option forwarded 사용 시, haproxy가 forwarded 헤더를 서버로 전송되는 요청에 삽입
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;forwarded 헤더는 XFF 헤더의 표준화된 버전이지만, 실제 사용 빈도는 적음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;HTTP 헤더를 추가하는 방식이므로, HTTP 모드에서 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;sample&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;haproxy.cfg&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1753789519712&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;frontend main
        bind *:80
        default_backend app
        mode tcp


backend app
        option forwarded by-expr src ✅
        mode http&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;haproxy&amp;nbsp;&amp;rarr;&amp;nbsp;apache&amp;nbsp;호출&amp;nbsp;시,&amp;nbsp;forwarded&amp;nbsp;헤더에&amp;nbsp;by&amp;nbsp;구문으로&amp;nbsp;클라이언트&amp;nbsp;IP가&amp;nbsp;추가&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;1354&quot; data-origin-height=&quot;526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dvhvv5/btsPB0J6BA7/FOiWSlzUhFPJrzdksDbOs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dvhvv5/btsPB0J6BA7/FOiWSlzUhFPJrzdksDbOs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dvhvv5/btsPB0J6BA7/FOiWSlzUhFPJrzdksDbOs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdvhvv5%2FbtsPB0J6BA7%2FFOiWSlzUhFPJrzdksDbOs0%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;1354&quot; height=&quot;526&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;1354&quot; data-origin-height=&quot;526&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;forwarded 헤더보다는 XFF 헤더를 주로 사용하기 때문에, apache &amp;rarr; application 호출 부분은 생략&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;방안 4. PROXY protocol &lt;i&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&amp;rarr; 이번 포스팅의 핵심!&lt;/span&gt;&lt;/i&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Proxy Protocol은 HAProxy Technologies에서 개발한 네트워크 프로토콜로, &lt;u&gt;&lt;b&gt;TCP 연결에 헤더를 추가하여 클라이언트 IP 주소를 보존&lt;/b&gt;&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;단, 이 방법을 사용하려면 &lt;u&gt;&lt;b&gt;발신자와 수신자 모두 이 프로토콜을 지원하고 활성화가 필요&lt;/b&gt;&lt;/u&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;i&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;이번 테스트에서 사용한 Apache의 경우, Proxy Protocol 모듈 활성화 필요&lt;/span&gt;&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;sample: HTTP&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;haproxy.cfg
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버와 통신 시, proxy protocol을 사용&lt;/li&gt;
&lt;li&gt;HTTP 헤더를 추가하는 방식이 아니므로 backend의 모드는 tcp로 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1753789733508&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;frontend main
        bind *:80
        default_backend app
        mode http


backend app
        server app1 192.168.64.148:80 check send-proxy ✅
        mode tcp ✅&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;apache conf
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;proxy protocol 활성화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1753789758236&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;LoadModule proxy_protocol_module /home/ubuntu/mod-proxy-protocol/.libs/mod_proxy_protocol.so ✅

...

&amp;lt;VirtualHost *:80&amp;gt;
  ServerName ubuntu.test.local

  ProxyProtocol On ✅
  
  ProxyPass / http://192.168.64.147:8080/
  ProxyPassReverse / http://192.168.64.147:8080/
&amp;lt;/VirtualHost&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;haproxy &amp;rarr; apache 호출 시, HTTP API 호출 이전에 프록시 프로토콜 관련 정보 세팅&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;2634&quot; data-origin-height=&quot;448&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGw1Pl/btsPDZ334Yx/xGtqmpwIjjYMVjLIm7gUM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGw1Pl/btsPDZ334Yx/xGtqmpwIjjYMVjLIm7gUM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGw1Pl/btsPDZ334Yx/xGtqmpwIjjYMVjLIm7gUM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGw1Pl%2FbtsPDZ334Yx%2FxGtqmpwIjjYMVjLIm7gUM1%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;2634&quot; height=&quot;448&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;2634&quot; data-origin-height=&quot;448&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;apache&amp;nbsp;&amp;rarr;&amp;nbsp;application&amp;nbsp;호출&amp;nbsp;시,&amp;nbsp;XFF&amp;nbsp;헤더에&amp;nbsp;클라이언트&amp;nbsp;IP를&amp;nbsp;추가&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;11.png&quot; data-origin-width=&quot;1368&quot; data-origin-height=&quot;604&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dAvda6/btsPDrzYik6/LkqWhoiIYpEmgWHVkl4wmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dAvda6/btsPDrzYik6/LkqWhoiIYpEmgWHVkl4wmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dAvda6/btsPDrzYik6/LkqWhoiIYpEmgWHVkl4wmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdAvda6%2FbtsPDrzYik6%2FLkqWhoiIYpEmgWHVkl4wmK%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;1368&quot; height=&quot;604&quot; data-filename=&quot;11.png&quot; data-origin-width=&quot;1368&quot; data-origin-height=&quot;604&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;proxy protocol의 장점 ✅&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 헤더의 값을 추가해서 클라이언트 IP를 보존하는 방식의 문제는 HTTP API를 사용하지 않으면 클라이언트 IP를 보존할 수 없다는 것인데, proxy protocol을 통해 &lt;u&gt;&lt;b&gt;TCP/IP를 활용해 메세지를 전송하는 모든 상위 계층 프로토콜에서도 클라이언트 IP 주소를 보존할 수 있음&lt;/b&gt;&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;HTTP 하위 계층에서 동작하는 방식이므로, &lt;u&gt;&lt;b&gt;HTTPS를 통한 API를 호출할 경우에도 SSL Bridging이 필요없음&lt;/b&gt;&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;sample: HTTPS&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;haproxy.cfg&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1753789975207&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;frontend tls_main
        bind *:443
        default_backend tls_app
        mode tcp

backend tls_app
        balance roundrobin
        server app1 192.168.64.148:443 check send-proxy ✅
        mode tcp ✅&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;apache conf&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1753789984588&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;VirtualHost *:443&amp;gt;
  ServerName ubuntu.test.local

  ProxyProtocol On ✅

  SSLEngine on ✅
  SSLCertificateFile ../certs/server.crt
  SSLCertificateKeyFile ../certs/server.key
  SSLCACertificateFile ../certs/root.pem

  ProxyPass / http://192.168.64.147:8080/
  ProxyPassReverse / http://192.168.64.147:8080/
&amp;lt;/VirtualHost&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;haproxy &amp;rarr; apache 호출 시, TLS 통신 전에 source address와 destination address를 먼저 전달한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;2626&quot; data-origin-height=&quot;672&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CM1XD/btsPBmfXHeR/O4Yai74hS9M8Leu3adlpqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CM1XD/btsPBmfXHeR/O4Yai74hS9M8Leu3adlpqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CM1XD/btsPBmfXHeR/O4Yai74hS9M8Leu3adlpqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCM1XD%2FbtsPBmfXHeR%2FO4Yai74hS9M8Leu3adlpqk%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;2626&quot; height=&quot;672&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;2626&quot; data-origin-height=&quot;672&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;apache(SSL&amp;nbsp;termination)&amp;nbsp;&amp;rarr;&amp;nbsp;application&amp;nbsp;호출&amp;nbsp;시,&amp;nbsp;XFF&amp;nbsp;헤더에&amp;nbsp;클라이언트&amp;nbsp;IP&amp;nbsp;추가&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;13.png&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HEdmC/btsPB6KiY4G/Zk6ndZdug5hoX918mMtT4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HEdmC/btsPB6KiY4G/Zk6ndZdug5hoX918mMtT4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HEdmC/btsPB6KiY4G/Zk6ndZdug5hoX918mMtT4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHEdmC%2FbtsPB6KiY4G%2FZk6ndZdug5hoX918mMtT4K%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;1360&quot; height=&quot;614&quot; data-filename=&quot;13.png&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고 자료  &amp;zwj;♂️&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&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.haproxy.com/documentation/haproxy-configuration-tutorials/proxying-essentials/client-ip-preservation/&quot;&gt;https://www.haproxy.com/documentation/haproxy-configuration-tutorials/proxying-essentials/client-ip-preservation/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.haproxy.com/documentation/haproxy-configuration-manual/latest/#option%20forwardfor&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.haproxy.com/documentation/haproxy-configuration-manual/latest/#option forwardfor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.haproxy.com/blog/use-the-proxy-protocol-to-preserve-a-clients-ip-address&quot;&gt;https://www.haproxy.com/blog/use-the-proxy-protocol-to-preserve-a-clients-ip-address&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/roadrunner2/mod-proxy-protocol&quot;&gt;https://github.com/roadrunner2/mod-proxy-protocol&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>haproxy</category>
      <category>client IP</category>
      <category>forwarded</category>
      <category>HAProxy</category>
      <category>proxy protocol</category>
      <category>X-Forwarded-For</category>
      <category>XFF</category>
      <category>클라이언트 IP</category>
      <author>시리어스강</author>
      <guid isPermaLink="true">https://seriouskang.tistory.com/18</guid>
      <comments>https://seriouskang.tistory.com/18#entry18comment</comments>
      <pubDate>Tue, 29 Jul 2025 20:57:42 +0900</pubDate>
    </item>
    <item>
      <title>[linux] 일반 유저로 1024 미만의 포트 사용하기</title>
      <link>https://seriouskang.tistory.com/17</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://seriouskang.tistory.com/16&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;지난&amp;nbsp;글&lt;/a&gt;에&amp;nbsp;이어서&amp;nbsp;일반&amp;nbsp;유저로&amp;nbsp;1024&amp;nbsp;미만의&amp;nbsp;포트(==&amp;nbsp;&lt;code&gt;privileged&lt;/code&gt;&amp;nbsp;포트)를&amp;nbsp;사용하는&amp;nbsp;것에&amp;nbsp;대해&amp;nbsp;정리해보려고&amp;nbsp;한다.&amp;nbsp;결과부터&amp;nbsp;얘기하면&amp;nbsp;커널&amp;nbsp;파라미터를&amp;nbsp;조정하는&amp;nbsp;방식으로&amp;nbsp;구성할&amp;nbsp;예정이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Untitled1.png&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;1214&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L7p8U/btsGMAmNgEc/gmzDV7knVnJ9GRIjxYW9nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L7p8U/btsGMAmNgEc/gmzDV7knVnJ9GRIjxYW9nk/img.png&quot; data-alt=&quot;안되는거 알아요&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L7p8U/btsGMAmNgEc/gmzDV7knVnJ9GRIjxYW9nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL7p8U%2FbtsGMAmNgEc%2FgmzDV7knVnJ9GRIjxYW9nk%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;335&quot; height=&quot;419&quot; data-filename=&quot;Untitled1.png&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;1214&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;안되는거 알아요&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. 기본 설정으로 일반 유저가 privileged 포트를 사용할 경우&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저 nginx 컨테이너의 포트를 privileged 포트 중 하나에 바인딩하면 어떤 문제가 발생하는지 알아보자. &lt;i&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;테스트 환경은 &lt;code&gt;Ubuntu&amp;nbsp;22.04.4&amp;nbsp;LTS&lt;/code&gt;이다.&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저 nginx 이미지를 받고&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1713661959676&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ podman pull docker.io/ngin&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;privileged 포트 중 하나인 443 포트에 컨테이너의 80번 포트를 바인딩하면&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1713661977705&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ podman run --rm -d --name nginx -p 443:80 docker.io/library/nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음과 같은 메세지와 함께 컨테이너가 뜨지 않는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1713661995273&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Error: rootlessport cannot expose privileged port 443,
you can add 'net.ipv4.ip_unprivileged_port_start=443' to /etc/sysctl.conf (currently 1024), 
or choose a larger port number (&amp;gt;= 1024): listen tcp 0.0.0.0:443: bind: permission denied&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;에러 메세지를 보면 알 수 있듯이 &lt;code&gt;net.ipv4.ip_unprivileged_port_start&lt;/code&gt; 값을 &lt;code&gt;/etc/sysctl.conf&lt;/code&gt;에 추가하거나, 1024 이상 포트를 사용해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;1890&quot; data-origin-height=&quot;122&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEB5Dv/btsGOG6BMix/C9sk6Hps4HkL3Xmj5ECrP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEB5Dv/btsGOG6BMix/C9sk6Hps4HkL3Xmj5ECrP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEB5Dv/btsGOG6BMix/C9sk6Hps4HkL3Xmj5ECrP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEB5Dv%2FbtsGOG6BMix%2FC9sk6Hps4HkL3Xmj5ECrP1%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;1890&quot; height=&quot;122&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;1890&quot; data-origin-height=&quot;122&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. 커널 파라미터 조정&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; font-family: 'Nanum Gothic';&quot;&gt;&lt;i&gt;커널 라파미터란 커널의 작동 방식을 제어하는 방법으로, 커널 파라미터를 핸들링하기 위해 &lt;code&gt;sysctl&lt;/code&gt; 커맨드를 활용하고 설정 값은 &lt;code&gt;/etc/sysctl.conf&lt;/code&gt;에서 수정 및 확인할 수 있다.&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1024 이상의 포트를 사용하는게 우리의 목적이 아니므로, 에러 메세지에서 나온 것처럼 커널 파라미터(&lt;code&gt;net.ipv4.ip_unprivileged_port_start&lt;/code&gt;)를 추가하는 방식으로 문제를 해결해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저 privileged 포트가 아닌 포트는 몇 번부터인지 설정하는 &lt;code&gt;net.ipv4.ip_unprivileged_port_start&lt;/code&gt;&amp;nbsp;파라미터부터 확인해보면 1024로 나오는 것을 알 수 있는데, 이는 일반 계정은 1024 포트부터 사용할 수 있다는 뜻이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1713662147290&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sysctl net.ipv4.ip_unprivileged_port_start
net.ipv4.ip_unprivileged_port_start = 1024&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;해당 커널 파라미터을 어떻게 설정하냐에 따라 일반 유저가 사용할 수 있는 포트의 범위가 정해지는데&lt;/b&gt;&lt;/span&gt;, 443 포트를 바인딩할 예정이므로 설정 파일(&lt;code&gt;/etc/sysctl.conf&lt;/code&gt;)에 443으로 설정하면 된다. 참고로 해당 설정 파일은 기본적으로 root만 수정할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;76&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/balR8J/btsGNr3t8RI/XJVZiUkqG9CjkTERaCgZ51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/balR8J/btsGNr3t8RI/XJVZiUkqG9CjkTERaCgZ51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/balR8J/btsGNr3t8RI/XJVZiUkqG9CjkTERaCgZ51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbalR8J%2FbtsGNr3t8RI%2FXJVZiUkqG9CjkTERaCgZ51%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;526&quot; height=&quot;60&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;76&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;net.ipv4.ip_unprivileged_port_start&lt;/code&gt; 파라미터를 이전에 설정했는지 확인한 뒤에, 설정된 값이 없으면 443으로 설정한다. &lt;i&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&amp;rarr; 당연하지만 기존에 설정된 값이 있으면 그 값을 수정한다. &lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1713662218994&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cat /etc/sysctl.conf | grep net.ipv4.ip_unprivileged_port_start

# 아래 커맨드는 root 권한으로 수행해야 한다
$ echo 'net.ipv4.ip_unprivileged_port_start=443' &amp;gt;&amp;gt; /etc/sysctl.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 root 권한으로 수정된 커널 파라미터를 로드한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1713662249572&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sysctl -p
net.ipv4.ip_unprivileged_port_start = 443&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3. 일반 유저로 privileged 포트 사용하기&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이전 단계를 통해 unprivileged 대상이 되는 포트의 시작점이 443으로 바뀐 것을 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1713662265487&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sysctl net.ipv4.ip_unprivileged_port_start
net.ipv4.ip_unprivileged_port_start = 443&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러므로 &lt;b&gt;일반 계정이 443 포트를 사용해도 된다는 것을 확인&lt;/b&gt;할 수 있다!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;1102&quot; data-origin-height=&quot;742&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/enFly3/btsGL1x4gTb/Aeko1c54axchzxpOrAKCv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/enFly3/btsGL1x4gTb/Aeko1c54axchzxpOrAKCv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/enFly3/btsGL1x4gTb/Aeko1c54axchzxpOrAKCv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FenFly3%2FbtsGL1x4gTb%2FAeko1c54axchzxpOrAKCv0%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;694&quot; height=&quot;467&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;1102&quot; data-origin-height=&quot;742&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;당연하지만 설정한 커널 파라미터보다 낮은 포트는 privileged 포트가 되므로, 일반 계정으론 사용할 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;1872&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdPR8w/btsGNsuBcFm/lQ5src1ZPJsYABU2vXKxg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdPR8w/btsGNsuBcFm/lQ5src1ZPJsYABU2vXKxg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdPR8w/btsGNsuBcFm/lQ5src1ZPJsYABU2vXKxg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdPR8w%2FbtsGNsuBcFm%2FlQ5src1ZPJsYABU2vXKxg1%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;1872&quot; height=&quot;96&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;1872&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;참고 자료  &amp;zwj;♂️&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://www.w3.org/Daemon/User/Installation/PrivilegedPorts.html&quot;&gt;https://www.w3.org/Daemon/User/Installation/PrivilegedPorts.html&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://www.usenix.org/conference/2002-linux-kernel-developers-summit/kernel-parameters&quot;&gt;https://www.usenix.org/conference/2002-linux-kernel-developers-summit/kernel-parameters&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>linux</category>
      <category>1024</category>
      <category>net.ipv4.ip_unprivileged_port_start</category>
      <category>privileged port</category>
      <category>Root</category>
      <category>rootless</category>
      <category>sudo</category>
      <category>sysctl</category>
      <category>일반 유저</category>
      <category>커널 파라미터</category>
      <author>시리어스강</author>
      <guid isPermaLink="true">https://seriouskang.tistory.com/17</guid>
      <comments>https://seriouskang.tistory.com/17#entry17comment</comments>
      <pubDate>Sun, 21 Apr 2024 10:19:16 +0900</pubDate>
    </item>
    <item>
      <title>[linux] 유저 권한으로 서비스 실행하고 로그아웃에도 서비스 유지하기</title>
      <link>https://seriouskang.tistory.com/16</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개인 서버라면&amp;nbsp;&lt;code&gt;root&lt;/code&gt; 계정이나 &lt;code&gt;sudo&lt;/code&gt; 커맨드를 고민 없이 사용하지만, 실무에서는 서버 관리자가 아니라면 그러기가 쉽지 않다. 그렇다고 매번 서버 관리자에게 작업을 요청할 수 없으니, 유저 권한으로 할 수 있는 것들은 최대한 해야하겠지&amp;hellip; &amp;zwj;↕️&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이번 포스팅에서는 유저 권한으로 서비스를 실행하는 방법과 계정 로그아웃 상황에서도 서비스를 유지하는 방법에 대해 정리해본다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;339&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zdN1F/btsGLB7hCKJ/sDx8ubeKnoA9tcIInn9rh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zdN1F/btsGLB7hCKJ/sDx8ubeKnoA9tcIInn9rh0/img.png&quot; data-alt=&quot;네네, 압니다요&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zdN1F/btsGLB7hCKJ/sDx8ubeKnoA9tcIInn9rh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzdN1F%2FbtsGLB7hCKJ%2FsDx8ubeKnoA9tcIInn9rh0%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;602&quot; height=&quot;339&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;339&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;네네, 압니다요&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. 테스트 스크립트 생성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;유저&amp;nbsp;서비스로&amp;nbsp;등록할 테스트 스크립트(&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;&amp;rarr; 1초 간격으로 현재 시간을 tmp 경로에 남김&lt;/i&gt;&lt;/span&gt;)는&amp;nbsp;다음과&amp;nbsp;같다.&amp;nbsp;해당&amp;nbsp;스크립트를&amp;nbsp;유저의&amp;nbsp;홈&amp;nbsp;경로(&lt;code&gt;~/test.sh&lt;/code&gt;)에 저장하여 사용할 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1713589398604&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#!/bin/bash

while true; do
  echo `date` &amp;gt;&amp;gt; /tmp/date.log
  sleep 1
done&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;스크립트 실행을 위해서 실행 권한도 변경해준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1713589417794&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ chmod u+x ~/test.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. 서비스 유닛 파일 생성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;유저&amp;nbsp;레벨의&amp;nbsp;서비스&amp;nbsp;유닛&amp;nbsp;파일&amp;nbsp;경로는&amp;nbsp;&lt;code&gt;~/.config/systemd/user&lt;/code&gt;에&amp;nbsp;저장해서&amp;nbsp;사용한다.&amp;nbsp;디렉토리가&amp;nbsp;없다면&amp;nbsp;생성해서&amp;nbsp;서비스&amp;nbsp;유닛&amp;nbsp;파일을&amp;nbsp;저장한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1713589455418&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ mkdir -p ~/.config/systemd/user&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서비스&amp;nbsp;유닛&amp;nbsp;파일(&lt;code&gt;~/.config/systemd/user/user-test.service&lt;/code&gt;)은&amp;nbsp;이전&amp;nbsp;단계에서&amp;nbsp;생성된&amp;nbsp;파일을&amp;nbsp;실행하도록&amp;nbsp;구성했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1713589490739&quot; class=&quot;ini&quot; data-ke-language=&quot;ini&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[Unit]
Description=Test User-Level Service

[Service]
ExecStart=/home/foo/test.sh
Restart=always

[Install]
WantedBy=default.target&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3. 서비스 실행&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이제 추가한 서비스 유닛 파일을 다음 명령어를 통해 로드하고&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1713589531468&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ systemctl --user daemon-reload&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서비스를 실행한다!&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1713589543974&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ systemctl --user start user-test&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서비스의 상태와 실행 결과를 확인하면 문제 없이 잘 수행되는 것을 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;1270&quot; data-origin-height=&quot;376&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dPzme0/btsGNGTuzi4/tIDCnuiAJF8X6amw6PkJz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dPzme0/btsGNGTuzi4/tIDCnuiAJF8X6amw6PkJz0/img.png&quot; data-alt=&quot;서비스 상태&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dPzme0/btsGNGTuzi4/tIDCnuiAJF8X6amw6PkJz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdPzme0%2FbtsGNGTuzi4%2FtIDCnuiAJF8X6amw6PkJz0%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;1270&quot; height=&quot;376&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;1270&quot; data-origin-height=&quot;376&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;서비스 상태&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.gif&quot; data-origin-width=&quot;554&quot; data-origin-height=&quot;324&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JgpvT/btsGMEbp4Gn/O3p8UuqgiqDwh71NbM2dX1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JgpvT/btsGMEbp4Gn/O3p8UuqgiqDwh71NbM2dX1/img.gif&quot; data-alt=&quot;의도한대로 1초마다 현재 시간을 잘 찍어준다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JgpvT/btsGMEbp4Gn/O3p8UuqgiqDwh71NbM2dX1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/JgpvT/btsGMEbp4Gn/O3p8UuqgiqDwh71NbM2dX1/img.gif&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;554&quot; height=&quot;324&quot; data-filename=&quot;3.gif&quot; data-origin-width=&quot;554&quot; data-origin-height=&quot;324&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;의도한대로 1초마다 현재 시간을 잘 찍어준다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;4. 유저 로그아웃에도 서비스 유지하기&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기까지 했으면 유저 권한으로 서비스를 잘 실행했을 수도 있다고 볼 수 있지만, &lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;문제는 유저가 로그아웃을 하게되면 서비스가 멈추게 된다.&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt; &amp;rarr; 이번 포스팅을 작성한 계기이다.&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;4.gif&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tm2XL/btsGMfQpCsp/dscdmFCNxcm5W3ggTIudSk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tm2XL/btsGMfQpCsp/dscdmFCNxcm5W3ggTIudSk/img.gif&quot; data-alt=&quot;서비스를 실행한 계정에서 로그아웃을 하면, 서비스가 일정 시간이 지난 후에 멈추는 것을 확인할 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tm2XL/btsGMfQpCsp/dscdmFCNxcm5W3ggTIudSk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/tm2XL/btsGMfQpCsp/dscdmFCNxcm5W3ggTIudSk/img.gif&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;474&quot; height=&quot;288&quot; data-filename=&quot;4.gif&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;288&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;서비스를 실행한 계정에서 로그아웃을 하면, 서비스가 일정 시간이 지난 후에 멈추는 것을 확인할 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다시&amp;nbsp;로그인을&amp;nbsp;한&amp;nbsp;뒤&amp;nbsp;서비스&amp;nbsp;상태를&amp;nbsp;확인해보면&amp;nbsp;&lt;code&gt;inactive&lt;/code&gt;로&amp;nbsp;변경된&amp;nbsp;것을&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;4.5.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccVU0R/btsGM142t7H/zfjZke4EHf6BJKaXHAwGX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccVU0R/btsGM142t7H/zfjZke4EHf6BJKaXHAwGX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccVU0R/btsGM142t7H/zfjZke4EHf6BJKaXHAwGX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccVU0R%2FbtsGM142t7H%2FzfjZke4EHf6BJKaXHAwGX0%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;1262&quot; height=&quot;340&quot; data-filename=&quot;4.5.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서비스를 유저가 로그아웃을 해도 계속 실행되도록 하기 위해서는 아래의 명령어를 사용하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1713589708224&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ loginctl enable-linger $USER&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러면&amp;nbsp;유저의&amp;nbsp;&lt;code&gt;Linger&lt;/code&gt;&amp;nbsp;속성이&amp;nbsp;yes로&amp;nbsp;변경되고,&amp;nbsp;유저가&amp;nbsp;로그아웃을&amp;nbsp;해도&amp;nbsp;유저&amp;nbsp;서비스가&amp;nbsp;유지된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDb94M/btsGMKbnbNY/IiC6gQNGqzesPyvCi7V121/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDb94M/btsGMKbnbNY/IiC6gQNGqzesPyvCi7V121/img.png&quot; data-alt=&quot;참고로, lingersms 남다/계속되다라는 뜻&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDb94M/btsGMKbnbNY/IiC6gQNGqzesPyvCi7V121/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDb94M%2FbtsGMKbnbNY%2FIiC6gQNGqzesPyvCi7V121%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;546&quot; height=&quot;454&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;454&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;참고로, lingersms 남다/계속되다라는 뜻&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;테스트&amp;nbsp;결과를&amp;nbsp;살펴보면,&amp;nbsp;유저가&amp;nbsp;로그아웃을&amp;nbsp;해도&amp;nbsp;서비스가&amp;nbsp;유지되고&amp;nbsp;다시&amp;nbsp;접속해&amp;nbsp;서비스&amp;nbsp;상태를&amp;nbsp;확인해도&amp;nbsp;&lt;code&gt;active&lt;/code&gt;인&amp;nbsp;것을&amp;nbsp;알&amp;nbsp;수&amp;nbsp;있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;6.gif&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLPzHY/btsGL1EHDAG/JWLTYumhT0C64kjNo3KeF1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLPzHY/btsGL1EHDAG/JWLTYumhT0C64kjNo3KeF1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLPzHY/btsGL1EHDAG/JWLTYumhT0C64kjNo3KeF1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cLPzHY/btsGL1EHDAG/JWLTYumhT0C64kjNo3KeF1/img.gif&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;678&quot; height=&quot;374&quot; data-filename=&quot;6.gif&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>linux</category>
      <category>daemon-reload</category>
      <category>enable-linger</category>
      <category>loginctl</category>
      <category>service</category>
      <category>show-user</category>
      <category>서비스</category>
      <category>유저 권한</category>
      <author>시리어스강</author>
      <guid isPermaLink="true">https://seriouskang.tistory.com/16</guid>
      <comments>https://seriouskang.tistory.com/16#entry16comment</comments>
      <pubDate>Sat, 20 Apr 2024 14:10:31 +0900</pubDate>
    </item>
    <item>
      <title>[linux] 오프라인 환경(air gap)을 위한 yum repository 구축하기</title>
      <link>https://seriouskang.tistory.com/15</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너&amp;nbsp;기반&amp;nbsp;서비스&amp;nbsp;운영&amp;nbsp;업무를&amp;nbsp;맡게&amp;nbsp;되면서&amp;nbsp;air&amp;nbsp;gap&amp;nbsp;환경에&amp;nbsp;&lt;code&gt;OCP&lt;/code&gt;와&amp;nbsp;&lt;code&gt;OKD&lt;/code&gt; 설치를&amp;nbsp;진행하게&amp;nbsp;되었는데,&amp;nbsp;설치하는&amp;nbsp;과정&amp;nbsp;중에&amp;nbsp;&lt;code&gt;yum&amp;nbsp;repository&lt;/code&gt;를&amp;nbsp;구축하는&amp;nbsp;부분이&amp;nbsp;있어&amp;nbsp;연습&amp;nbsp;겸&amp;nbsp;포스팅을&amp;nbsp;해보려고&amp;nbsp;한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.gif&quot; data-origin-width=&quot;450&quot; data-origin-height=&quot;379&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zi8Pw/btsF4YmkmPk/fVeYUAp98epYrI2AePQN70/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zi8Pw/btsF4YmkmPk/fVeYUAp98epYrI2AePQN70/img.gif&quot; data-alt=&quot;air gap 환경에선 신경 쓸게 곱절은 늘어나는거 같다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zi8Pw/btsF4YmkmPk/fVeYUAp98epYrI2AePQN70/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/Zi8Pw/btsF4YmkmPk/fVeYUAp98epYrI2AePQN70/img.gif&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;450&quot; height=&quot;379&quot; data-filename=&quot;1.gif&quot; data-origin-width=&quot;450&quot; data-origin-height=&quot;379&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;air gap 환경에선 신경 쓸게 곱절은 늘어나는거 같다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. 테스트 개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;air&amp;nbsp;gap&amp;nbsp;환경을&amp;nbsp;위해&amp;nbsp;다음와&amp;nbsp;같은&amp;nbsp;순서로&amp;nbsp;테스트&amp;nbsp;환경을&amp;nbsp;구축할&amp;nbsp;것이다.&amp;nbsp;테스트를&amp;nbsp;위해&amp;nbsp;&lt;code&gt;aws&lt;/code&gt;를&amp;nbsp;사용했는데,&amp;nbsp;&lt;code&gt;aws&lt;/code&gt;를 사용하지 않을 경우 1, 3번은 다른 방식으로 구성해도 당연히 괜찮다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;aws&lt;/code&gt;의 &lt;code&gt;private subnet&lt;/code&gt;에 서버/클라이언트용 인스턴스 생성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;NAT gateway&lt;/code&gt;를 통해 필요한 패키지를 &lt;code&gt;yum repository&lt;/code&gt;가 될 인스턴스에 다운로드&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;NAT gateway&lt;/code&gt;를 제거하여 &lt;code&gt;private subnet&lt;/code&gt; 내에 있는 인스턴스를 air gap 상태로 변경&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이전 단계에서 구성한 &lt;code&gt;yum repository&lt;/code&gt; 정보를 클라이언트 인스턴스에 추가&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;패키지 다운로드 &lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. 테스트 인스턴스 생성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;air&amp;nbsp;gap&amp;nbsp;환경으로&amp;nbsp;구축을&amp;nbsp;위해&amp;nbsp;&lt;code&gt;private&amp;nbsp;subnet&lt;/code&gt;에&amp;nbsp;서버와&amp;nbsp;클라이언트가&amp;nbsp;될&amp;nbsp;인스턴스를&amp;nbsp;생성했다.&amp;nbsp;테스트&amp;nbsp;인스턴스의&amp;nbsp;OS는&amp;nbsp;&lt;code&gt;Amazon&amp;nbsp;Linux&lt;/code&gt;를&amp;nbsp;선택했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3. yum repository 구성&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;yum repository 구축&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아파치&amp;nbsp;웹&amp;nbsp;서버의&amp;nbsp;기본&amp;nbsp;디렉토리인&amp;nbsp;&lt;code&gt;/var/www/html&lt;/code&gt;를&amp;nbsp;사용해도&amp;nbsp;되지만,&amp;nbsp;별도의&amp;nbsp;디렉토리에&amp;nbsp;&lt;code&gt;rpm&lt;/code&gt;을&amp;nbsp;다운받아서&amp;nbsp;사용할&amp;nbsp;것이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711281508259&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo yum install -y createrepo
$ sudo mkdir -p /app/rpms
$ sudo createrepo /app/rpms&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;122&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MbZT9/btsF4YmksJf/IO8ZVPyXnUisz5GIm6gq50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MbZT9/btsF4YmksJf/IO8ZVPyXnUisz5GIm6gq50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MbZT9/btsF4YmksJf/IO8ZVPyXnUisz5GIm6gq50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMbZT9%2FbtsF4YmksJf%2FIO8ZVPyXnUisz5GIm6gq50%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;530&quot; height=&quot;122&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;122&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;패키지(rpm) 다운로드&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;샘플로&amp;nbsp;다운&amp;nbsp;받을&amp;nbsp;패키지는&amp;nbsp;구성한&amp;nbsp;인스턴스에&amp;nbsp;없는&amp;nbsp;&lt;code&gt;htop&lt;/code&gt;,&amp;nbsp;&lt;code&gt;tmux&lt;/code&gt;,&amp;nbsp;&lt;code&gt;ansible&lt;/code&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711281563319&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo yumdownloader --resolve --downloaddir=/app/rpms htop tmux ansible&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;repository 업데이트&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1711281577275&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo createrepo --update /app/rpms&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;httpd 설치&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;클라이언트 인스턴스에서 접속할 수 있도록 웹 서버를 설치한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711281586308&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo yum install -y httpd&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;참고로 테스트 환경의 아파치 버전은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;90&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PXklz/btsF3bT3E13/mysirPHbkYgrJIcg6O2ack/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PXklz/btsF3bT3E13/mysirPHbkYgrJIcg6O2ack/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PXklz/btsF3bT3E13/mysirPHbkYgrJIcg6O2ack/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPXklz%2FbtsF3bT3E13%2FmysirPHbkYgrJIcg6O2ack%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;470&quot; height=&quot;78&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;90&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;httpd 설정(httpd.conf) 변경&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기존에 테스트 환경에&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span&gt;&amp;nbsp;아파치 웹 서버를 사용하고 있다면, 각자의 환경에 맞춰 수정해서 사용하면 된다. 중요한 것은 &lt;/span&gt;&lt;code style=&quot;font-family: 'Nanum Gothic';&quot;&gt;DocumentRoot&lt;/code&gt;&lt;span&gt;를 패키지를 설치한 경로로 설정하는 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;DocumentRoot 수정&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711281680468&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# DocumentRoot &quot;/var/www/html&quot;
DocumentRoot &quot;/app/rpms&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Document 속성 추가&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711281704377&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Directory &quot;/app/rpms&quot;&amp;gt;
    AllowOverride None
    Options Indexes # 보안 이슈로 사용 주의. 관련 내용은 이후에 나올 &quot;패키지 확인&quot; 부분 참고
    Require all granted
&amp;lt;/Directory&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;추가 설정 파일 제외&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711281721986&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# IncludeOptional conf.d/*.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;httpd 재기동&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1711281734271&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo systemctl restart httpd&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;패키지 확인&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;웹 서버로 요청을 보내면 설치한 패키지 리스트들을 볼 수 있다. 참고로 실습 결과를 보여주기 위해 &lt;code&gt;httpd.conf&lt;/code&gt;에서&amp;nbsp;파일&amp;nbsp;목록&amp;nbsp;리스트를&amp;nbsp;노출하도록&amp;nbsp;설정&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;(Directory&amp;nbsp;-&amp;nbsp;Options&amp;nbsp;Indexes)&lt;/i&gt;&lt;/span&gt;을&amp;nbsp;해서&amp;nbsp;해당&amp;nbsp;리스트가&amp;nbsp;보이는거지만,&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;보안을&amp;nbsp;위해서는&amp;nbsp;해당&amp;nbsp;옵션을&amp;nbsp;사용하지&amp;nbsp;않는&amp;nbsp;것이&amp;nbsp;좋다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711281789978&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ curl localhost:80&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;1850&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7pOLA/btsF2xiZkXS/zHCkQCFW02qUnzeeG4x490/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7pOLA/btsF2xiZkXS/zHCkQCFW02qUnzeeG4x490/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7pOLA/btsF2xiZkXS/zHCkQCFW02qUnzeeG4x490/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7pOLA%2FbtsF2xiZkXS%2FzHCkQCFW02qUnzeeG4x490%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;671&quot; height=&quot;194&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;1850&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;4. air gap 환경 구성&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;변경 전&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;클라이언트 인스턴스에서 외부 요청을 보낼 경우, 요청이 처리가 되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711281836236&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ curl -I https://google.com&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;1014&quot; data-origin-height=&quot;304&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1gswI/btsF4YfyWt8/32r18KKvBU28gzDavtThj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1gswI/btsF4YfyWt8/32r18KKvBU28gzDavtThj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1gswI/btsF4YfyWt8/32r18KKvBU28gzDavtThj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1gswI%2FbtsF4YfyWt8%2F32r18KKvBU28gzDavtThj1%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;663&quot; height=&quot;199&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;1014&quot; data-origin-height=&quot;304&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;오프라인 환경(air gap) 구축&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;오프라인&amp;nbsp;환경&amp;nbsp;구축을&amp;nbsp;위해&amp;nbsp;&lt;code&gt;NAT&amp;nbsp;gateway&lt;/code&gt;를&amp;nbsp;삭제했다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;1928&quot; data-origin-height=&quot;316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfo7t9/btsF1ZGRi1O/gSDeCn70xIdtNZqkKSqm3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfo7t9/btsF1ZGRi1O/gSDeCn70xIdtNZqkKSqm3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfo7t9/btsF1ZGRi1O/gSDeCn70xIdtNZqkKSqm3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbfo7t9%2FbtsF1ZGRi1O%2FgSDeCn70xIdtNZqkKSqm3K%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;738&quot; height=&quot;121&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;1928&quot; data-origin-height=&quot;316&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이후 외부로 요청을 보낼 경우, 정상적으로 처리되지 않고 타임아웃이 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AzDtS/btsF1Sukqg6/N4IpZCZSw1iXVZfz79W4WK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AzDtS/btsF1Sukqg6/N4IpZCZSw1iXVZfz79W4WK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AzDtS/btsF1Sukqg6/N4IpZCZSw1iXVZfz79W4WK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAzDtS%2FbtsF1Sukqg6%2FN4IpZCZSw1iXVZfz79W4WK%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;705&quot; height=&quot;50&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;당연히 리눅스 패키지도 다운이 안된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;8.gif&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;296&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GuKdp/btsF3XBcz2Z/pwtS3QeQJVi8AO3nFVhVU1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GuKdp/btsF3XBcz2Z/pwtS3QeQJVi8AO3nFVhVU1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GuKdp/btsF3XBcz2Z/pwtS3QeQJVi8AO3nFVhVU1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/GuKdp/btsF3XBcz2Z/pwtS3QeQJVi8AO3nFVhVU1/img.gif&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;609&quot; height=&quot;192&quot; data-filename=&quot;8.gif&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;296&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;5. 클라이언트 인스턴스에서 패키지 다운로드&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이제&amp;nbsp;air&amp;nbsp;gap&amp;nbsp;환경이&amp;nbsp;구축되었으니,&amp;nbsp;클라이언트&amp;nbsp;인스턴스에서&amp;nbsp;이전&amp;nbsp;단계에&amp;nbsp;구축한&amp;nbsp;&lt;code&gt;yum&amp;nbsp;repository&lt;/code&gt;&amp;nbsp;설정을&amp;nbsp;추가해&amp;nbsp;테스트를&amp;nbsp;진행해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기존 repository 삭제&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;물론 삭제 대신 백업을 해도 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711281977420&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo rm /etc/yum.repos.d/*&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;yum repository 추가&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;구축한&amp;nbsp;&lt;code&gt;yum&amp;nbsp;repository&lt;/code&gt;를 바라볼 수 있도록 설정을 추가한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711282001232&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo bash -c 'cat &amp;lt;&amp;lt;EOF &amp;gt; /etc/yum.repos.d/air-gap-repo.repo
[air-gap-repo]
name=air-gap-repo
baseurl=http://[repository ip]
gpgcheck=0
enabled=1
EOF'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;yum repository 추가 확인&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;repository가&amp;nbsp;추가된&amp;nbsp;것을&amp;nbsp;확인할&amp;nbsp;수&amp;nbsp;있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711282024901&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ yum repolist 
repo id                repo name
air-gap-repo           air-gap-repo ✅&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;패키지 다운로드&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;yum repositoy&lt;/code&gt;에 받아둔 &lt;code&gt;htop&lt;/code&gt;, &lt;code&gt;tmux&lt;/code&gt;, &lt;code&gt;ansible&lt;/code&gt;을 설치하면 air gap 환경이지만 정상적으로 설치가 되는 것을 볼 수 있다  &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711282054448&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo yum install -y htop tmux ansible&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;1132&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caSnDH/btsF4yut2Gd/FwWWlUfMwRVjOR6zHuW0O0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caSnDH/btsF4yut2Gd/FwWWlUfMwRVjOR6zHuW0O0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caSnDH/btsF4yut2Gd/FwWWlUfMwRVjOR6zHuW0O0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaSnDH%2FbtsF4yut2Gd%2FFwWWlUfMwRVjOR6zHuW0O0%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;734&quot; height=&quot;332&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;1132&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;당연하지만, 준비되지 않은 패키지(&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;&lt;code&gt;stress&lt;/code&gt;&lt;/i&gt;&lt;/span&gt;)는 설치할 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711282109023&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo yum install -y stress&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;651&quot; data-origin-height=&quot;71&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kHjQc/btsF3d5qG8y/K8LiPLQP9ztqQPdERfFw80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kHjQc/btsF3d5qG8y/K8LiPLQP9ztqQPdERfFw80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kHjQc/btsF3d5qG8y/K8LiPLQP9ztqQPdERfFw80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkHjQc%2FbtsF3d5qG8y%2FK8LiPLQP9ztqQPdERfFw80%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;651&quot; height=&quot;71&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;651&quot; data-origin-height=&quot;71&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;패키지 설치 확인&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;패키지가 잘 설치된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711282121814&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ yum list --installed | egrep &quot;htop|tmux|ansible&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;11.png&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;89&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K6xKm/btsF2Ny6K2W/BbyVMrpajSmvyDLuouV12k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K6xKm/btsF2Ny6K2W/BbyVMrpajSmvyDLuouV12k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K6xKm/btsF2Ny6K2W/BbyVMrpajSmvyDLuouV12k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK6xKm%2FbtsF2Ny6K2W%2FBbyVMrpajSmvyDLuouV12k%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;729&quot; height=&quot;80&quot; data-filename=&quot;11.png&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;89&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;</description>
      <category>linux</category>
      <category>air gap</category>
      <category>createrepo</category>
      <category>yum repository</category>
      <category>오프라인</category>
      <author>시리어스강</author>
      <guid isPermaLink="true">https://seriouskang.tistory.com/15</guid>
      <comments>https://seriouskang.tistory.com/15#entry15comment</comments>
      <pubDate>Sun, 24 Mar 2024 21:12:55 +0900</pubDate>
    </item>
    <item>
      <title>[container] 리눅스 기능을 활용해 컨테이너 만들어보기</title>
      <link>https://seriouskang.tistory.com/14</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;쿠버네티스 관련 공부를 하며 파드에 대한 기본 요소를 설명한 부분을 봤는데, 꽤나 흥미로운 주제라 이번 기회에 리눅스/컨테이너에 대해 공부하는 겸 리눅스 기능을 활용해 컨테이너를 만들어보려고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;1352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YIkSA/btsF0aWM7q2/uVXyIJFELEp4l4KZcH6FH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YIkSA/btsF0aWM7q2/uVXyIJFELEp4l4KZcH6FH0/img.png&quot; data-alt=&quot;저도 그렇습니다  &quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YIkSA/btsF0aWM7q2/uVXyIJFELEp4l4KZcH6FH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYIkSA%2FbtsF0aWM7q2%2FuVXyIJFELEp4l4KZcH6FH0%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;470&quot; height=&quot;548&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;1352&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;저도 그렇습니다  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. 개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;작업 순서&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;실습 환경 구축&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;root 디렉토리 변경&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;데이터 제공 및 컨테이너 데이터 영속화&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;프로세스 격리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;네트워크 격리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;리소스 제한&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;주사용 기능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;&lt;b&gt;chroot&lt;/b&gt;&lt;/code&gt;&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Change Root Directory&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;현재 실행 중인 프로세스와 차일드 프로세스 그룹에서 루트 디렉토리를 변경한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이렇게 수정된 환경에서 실행되는 프로그램은 지정된 디렉토리 트리 밖의 파일들에 일반적으로는 접근이 불가능한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;&lt;b&gt;mount&lt;/b&gt;&lt;/code&gt;&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;파일 시스템을 지정된 위치(마운트 위치)에서 사용 가능하게 만든다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;&lt;b&gt;unshare&lt;/b&gt;&lt;/code&gt;&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;새로운 네임스페이스에서 프로그램을 실행한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;&lt;b&gt;cgroup&lt;/b&gt;&lt;/code&gt;&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Control Groups&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;프로세스들의 리소스 사용(cpu, memory, disk i/o, network 등)을 제한하고 격리시킨다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. 실습 환경 구축&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이번 포스팅의 목적은 특정 os에서 발생하는 문제를 트러블 슈팅하는게 아니므로, 실습을 하기 편한 환경을 선택했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; font-family: 'Nanum Gothic';&quot;&gt;&lt;i&gt;사족을 달자면, &lt;code&gt;docker container&lt;/code&gt;로 실습 환경을 구축하려고 했지만, proc 디렉토리를 마운트할 때 permission 이슈로 실습이 의도된대로 되지 않아 &lt;code&gt;multipass&lt;/code&gt;로 vm을 생성했다. 그리고 ubuntu 22.04.6 LTS로 실습을 진행하다가, &lt;code&gt;cgroup&lt;/code&gt; 설정 관련 이슈로 20.04를 선택했다.&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;command&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711112053727&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 20.04.6 LTS
multipass launch 20.04 --name test-instance&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3. chroot를 사용해 루트 디렉토리 변경&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;목표&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;지정된 디렉토리 밖의 파일에는 접근하지 못하도록 루트 디렉토리를 변경한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;작업 순서&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;실행할 프로그램과 프로그램이 실행돼야 하는 파일 시스템의 위치 결정한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;프로세스가 실행될 환경을 생성한다. &amp;rarr; &lt;code&gt;bash&lt;/code&gt; 같이 필요한 리눅스 프로그램을 새로운 루트로 불러온다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;실행하고 싶은 프로그램을 &lt;code&gt;chroot&lt;/code&gt; 처리된 위치로 복사한다. &lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;command&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711114706113&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;container=/tmp/container
mkdir -p $container/{bin,lib,proc}

cp /usr/bin/{kill,ps} $container/bin
cp /bin/{bash,ls} $container/bin
cp -r /lib/* $container/lib

sudo mount -t proc proc $container/proc
sudo chroot $container /bin/bash&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;결과&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;루트 디렉토리에서에서 &lt;code&gt;ls&lt;/code&gt; 명령어를 사용하면, 컨테이너 내에 있는 파일만 노출되는 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;896&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IkkPg/btsF1KJmtQy/O4Herq9COiZGnYKKIDlKlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IkkPg/btsF1KJmtQy/O4Herq9COiZGnYKKIDlKlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IkkPg/btsF1KJmtQy/O4Herq9COiZGnYKKIDlKlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIkkPg%2FbtsF1KJmtQy%2FO4Herq9COiZGnYKKIDlKlK%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;641&quot; height=&quot;292&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;896&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;4. mount를 활용해 데이터 제공 및 컨테이너 데이터 영속화&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;목표&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;생성한 컨테이너로 특정 데이터를 가져온다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;컨테이너 데이터를 영속화한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;command&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711114799436&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;container=/tmp/container
mkdir -p $container/{bin,lib,proc,data}          # data 디렉토리 추가

cp /usr/bin/{kill,ps} $container/bin
cp /bin/{bash,ls} $container/bin
cp -r /lib/* $container/lib

sudo mount -t proc proc $container/proc
mkdir /tmp/test-data                             # 테스트 데이터 추가
touch /tmp/test-data/{dummy1,dummy2}             # 테스트 데이터 추가
sudo mount --bind /tmp/test-data $container/data # mount
sudo chroot $container /bin/bash&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;결과&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;도커 볼륨과 같이 컨테이너 내에 데이터를 제공하거나, 컨테이너 내에 있는 데이터를 영속화할 수 있게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;1270&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chW83v/btsF1cNdTPm/fPkpFd7oBJb4U5OpE6iqb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chW83v/btsF1cNdTPm/fPkpFd7oBJb4U5OpE6iqb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chW83v/btsF1cNdTPm/fPkpFd7oBJb4U5OpE6iqb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchW83v%2FbtsF1cNdTPm%2FfPkpFd7oBJb4U5OpE6iqb1%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;678&quot; height=&quot;283&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;1270&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;✅ 참고: 컨테이너 삭제&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너에 기능을 점진적으로 추가하는 과정에서 컨테이너를 삭제하고 다시 만들게 되는데, 아래와 같이 컨테이너를 삭제하는 스크립트를 만들어서 사용했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711114841313&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#!/bin/bash

sudo umount /tmp/container/proc
sudo umount /tmp/container/data
rm -rf /tmp/container
rm -rf /tmp/test-data&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;5. unshare를 활용해 프로세스 격리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이전&amp;nbsp;과정을&amp;nbsp;통해&amp;nbsp;생성한&amp;nbsp;컨테이너의&amp;nbsp;경우,&amp;nbsp;&lt;code&gt;chroot&lt;/code&gt; 커맨드를 사용해 루트로 지정된 디렉토리 밖의 디렉토리에 접근 할 수는 없지만 다른 프로세스를 kill 할 수 있다. 이것이 실제 컨테이너라면 전체 클러스터를 중단시킬 수 있는 취약점이 될 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;취약점 sample&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;분할된&amp;nbsp;화면&amp;nbsp;중&amp;nbsp;위에&amp;nbsp;있는&amp;nbsp;것이&amp;nbsp;&lt;code&gt;chroot&lt;/code&gt;&amp;nbsp;처리된&amp;nbsp;프로세스인데,&amp;nbsp;해당&amp;nbsp;프로세스에서&amp;nbsp;외부에&amp;nbsp;있는&amp;nbsp;프로세스&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;(아래에&amp;nbsp;있는&amp;nbsp;분할&amp;nbsp;화면인&amp;nbsp;vi&amp;nbsp;프로세스)&lt;/i&gt;&lt;/span&gt;를&amp;nbsp;kill을&amp;nbsp;할&amp;nbsp;수&amp;nbsp;있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;4.gif&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;670&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kwLZ9/btsF0i8crhb/mcTwCiX1obu1t7paavhNGk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kwLZ9/btsF0i8crhb/mcTwCiX1obu1t7paavhNGk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kwLZ9/btsF0i8crhb/mcTwCiX1obu1t7paavhNGk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/kwLZ9/btsF0i8crhb/mcTwCiX1obu1t7paavhNGk/img.gif&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;692&quot; height=&quot;516&quot; data-filename=&quot;4.gif&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;670&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;목표&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너화된 운영 환경을 구축할 때 우선적으로 해결해야 하는 문제 중 하나가 격리(isolation)이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이를 위해 &lt;code&gt;unshare&lt;/code&gt; 명령어를 사용해 &lt;code&gt;chroot-bash&lt;/code&gt;를 프로세스 공간이 완전히 격리된 터미널에서 실행한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ef5369; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;즉, 고립된 프로세스를 만든다.&lt;/b&gt; &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;현재 상태&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이전에 생성한 컨테이너에서 &lt;code&gt;ps -ax&lt;/code&gt; 커맨드를 통해 프로세스를 조회할 경우, 컨테이너 외부의 프로세스를 조회할 수 있는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dRkuPs/btsF03v4qNY/7iW6czyHs8xYO0qtSoYNz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dRkuPs/btsF03v4qNY/7iW6czyHs8xYO0qtSoYNz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dRkuPs/btsF03v4qNY/7iW6czyHs8xYO0qtSoYNz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdRkuPs%2FbtsF03v4qNY%2F7iW6czyHs8xYO0qtSoYNz1%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;705&quot; height=&quot;168&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;command&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;unshare&lt;/code&gt;을&amp;nbsp;통해&amp;nbsp;PID&amp;nbsp;네임스페이스를&amp;nbsp;만든다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711114959731&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;container=/tmp/container
mkdir -p $container/{bin,lib,proc,data}

cp /usr/bin/{kill,ps} $container/bin
cp /bin/{bash,ls} $container/bin
cp -r /lib/* $container/lib

sudo mount -t proc proc $container/proc
mkdir /tmp/test-data                             
touch /tmp/test-data/{dummy1,dummy2}             
sudo mount --bind /tmp/test-data $container/data 

# unshare 커맨드 추가
sudo unshare -fp --mount-proc=$container/proc chroot /tmp/container /bin/bash&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;결과&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;ps&amp;nbsp;-ax&lt;/code&gt;&amp;nbsp;커맨드를&amp;nbsp;통해&amp;nbsp;새로운&amp;nbsp;네임스페이스에서&amp;nbsp;프로세스가&amp;nbsp;실행됐음을&amp;nbsp;확인할&amp;nbsp;수&amp;nbsp;있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;1270&quot; data-origin-height=&quot;550&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bq70KO/btsF2T6z9QS/yriPKgl8JaJA71AGrDkUM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bq70KO/btsF2T6z9QS/yriPKgl8JaJA71AGrDkUM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bq70KO/btsF2T6z9QS/yriPKgl8JaJA71AGrDkUM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbq70KO%2FbtsF2T6z9QS%2FyriPKgl8JaJA71AGrDkUM1%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;638&quot; height=&quot;276&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;1270&quot; data-origin-height=&quot;550&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;6. unshare를 활용해 네트워크 격리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이전 과정을 통해 프로세스를 다른 프로세스들과 격리했지만, 여전히 같은 네트워크를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;현재 상태&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너(위 분할 화면)와 컨테이너 프로세스를 띄운 인스턴스(아래 분할 화면)가 동일한 네트워크 설정을 사용하는 것을 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;1392&quot; data-origin-height=&quot;1356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4e9uM/btsF0F9YDnq/8X2KjfGZKL6CvCBgAsMEo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4e9uM/btsF0F9YDnq/8X2KjfGZKL6CvCBgAsMEo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4e9uM/btsF0F9YDnq/8X2KjfGZKL6CvCBgAsMEo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4e9uM%2FbtsF0F9YDnq%2F8X2KjfGZKL6CvCBgAsMEo0%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;605&quot; height=&quot;589&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;1392&quot; data-origin-height=&quot;1356&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;목표&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;code&gt;unshare&lt;/code&gt; 명령어를 통해 네트워크를 격리한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;command&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;unshare&amp;nbsp;-n&lt;/code&gt;&amp;nbsp;옵션을&amp;nbsp;통해&amp;nbsp;네트워크&amp;nbsp;네임스페이스를&amp;nbsp;만든다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711115062265&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;container=/tmp/container
mkdir -p $container/{bin,lib,proc,data}

cp /usr/bin/{kill,ps,ip,curl} $container/bin # ip, curl 커맨드 추가
cp /bin/{bash,ls} $container/bin
cp -r /lib/* $container/lib

sudo mount -t proc proc $container/proc
mkdir /tmp/test-data                             
touch /tmp/test-data/{dummy1,dummy2}             
sudo mount --bind /tmp/test-data $container/data 

# unshare 커맨드의 n 옵션 추가
sudo unshare -fpn --mount-proc=$container/proc chroot /tmp/container /bin/bash&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;결과&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너 내 별도의 네트워크 네임스페이스가 생성된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;1302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cadYKL/btsF1K3FWUa/solJHiKYp3deJVTKlrIYLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cadYKL/btsF1K3FWUa/solJHiKYp3deJVTKlrIYLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cadYKL/btsF1K3FWUa/solJHiKYp3deJVTKlrIYLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcadYKL%2FbtsF1K3FWUa%2FsolJHiKYp3deJVTKlrIYLk%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;599&quot; height=&quot;606&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;1302&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;7. cgroup을 활용해 리소스 제한&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;목표&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;span style=&quot;font-family: 'Nanum Gothic'; color: #ef5369;&quot;&gt;&lt;code&gt;cgroup&lt;/code&gt;를&amp;nbsp;통해&amp;nbsp;컨테이너의&amp;nbsp;리소스를&amp;nbsp;제한한다.&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;command&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너 생성&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711115115253&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;container=/tmp/container
mkdir -p $container/{bin,lib,proc,data}

cp /usr/bin/{kill,ps,ip,curl,stress} $container/bin # stress 커맨드 추가
cp /bin/{bash,ls} $container/bin
cp -r /lib/* $container/lib

sudo mount -t proc proc $container/proc
mkdir /tmp/test-data                             
touch /tmp/test-data/{dummy1,dummy2}             
sudo mount --bind /tmp/test-data $container/data 

sudo unshare -fpn --mount-proc=$container/proc chroot /tmp/container /bin/bash&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너 외부에서 컨테이너의 리소스 제한. 예시에서는 cpu를 100ms(&lt;code&gt;cpu.cfs_period_us&lt;/code&gt;) 주기로 30ms(&lt;code&gt;cpu.cfs_quota_us&lt;/code&gt;)&amp;nbsp;동안&amp;nbsp;실행할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;설정했다.&amp;nbsp;즉,&amp;nbsp;0.3cpu를&amp;nbsp;사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711115159809&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo cgcreate -g cpu:container
sudo cgset -r cpu.cfs_quota_us=30000 container # cpu.cfs_period_us=100000
sudo sh -c &quot;echo {컨테이너 bash pid} &amp;gt; /sys/fs/cgroup/cpu/container/tasks&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;결과&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;리소스 제한 전&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;9.gif&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UwLFX/btsF2Odd15d/LFBri9AuiQj23dFk8LQhM1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UwLFX/btsF2Odd15d/LFBri9AuiQj23dFk8LQhM1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UwLFX/btsF2Odd15d/LFBri9AuiQj23dFk8LQhM1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/UwLFX/btsF2Odd15d/LFBri9AuiQj23dFk8LQhM1/img.gif&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;622&quot; height=&quot;438&quot; data-filename=&quot;9.gif&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;리소스 제한 후에는 cpu를 적게 사용하는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;10.gif&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dUgxHq/btsF11D71ws/gpboKfdXi5Xs1p21D9zydk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dUgxHq/btsF11D71ws/gpboKfdXi5Xs1p21D9zydk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dUgxHq/btsF11D71ws/gpboKfdXi5Xs1p21D9zydk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/dUgxHq/btsF11D71ws/gpboKfdXi5Xs1p21D9zydk/img.gif&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;622&quot; height=&quot;438&quot; data-filename=&quot;10.gif&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;참고 자료  &amp;zwj;♂️&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/Chroot&quot;&gt;https://ko.wikipedia.org/wiki/Chroot&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://www.ibm.com/docs/ko/aix/7.2?topic=m-mount-command&quot;&gt;https://www.ibm.com/docs/ko/aix/7.2?topic=m-mount-command&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/Cgroups&quot;&gt;https://ko.wikipedia.org/wiki/Cgroups&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://www.yes24.com/Product/Goods/120763051&quot;&gt;코어 쿠버네티스&lt;/a&gt; &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>container</category>
      <category>cgroup</category>
      <category>chroot</category>
      <category>Container</category>
      <category>mount</category>
      <category>namespace</category>
      <category>unshare</category>
      <author>시리어스강</author>
      <guid isPermaLink="true">https://seriouskang.tistory.com/14</guid>
      <comments>https://seriouskang.tistory.com/14#entry14comment</comments>
      <pubDate>Fri, 22 Mar 2024 22:51:55 +0900</pubDate>
    </item>
    <item>
      <title>[o11y] OpenTelemetry, Jaeger을 활용해 spring-boot 어플리케이션 분산 추적해보기</title>
      <link>https://seriouskang.tistory.com/13</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사내에서 어플리케이션 모니터링 관련하여 기존에 사용하던 상용 APM과 별개로, OpenTelemetry(&lt;code&gt;OTel&lt;/code&gt;) 기반의 Observability 환경을 준비해보자라는 의견이 있어 개인 공부 겸 포스팅을 해보려고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Baeldung 글을 참고하여, &lt;code&gt;OTel&lt;/code&gt;과 &lt;code&gt;Jaeger&lt;/code&gt;를 활용해 어플리케이션을 어떻게 분산 추적(distributed tracing)하는지 아주아주 간단한 예제로 살펴보자  &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btADsa/btsD2J0KJoO/UAl0zyUi98uKVoFCLeYrS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btADsa/btsD2J0KJoO/UAl0zyUi98uKVoFCLeYrS0/img.png&quot; data-alt=&quot;관찰하자&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btADsa/btsD2J0KJoO/UAl0zyUi98uKVoFCLeYrS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtADsa%2FbtsD2J0KJoO%2FUAl0zyUi98uKVoFCLeYrS0%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;487&quot; height=&quot;325&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;관찰하자&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. 기본 개념&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예제를&amp;nbsp;살펴보기&amp;nbsp;전에&amp;nbsp;주로&amp;nbsp;언급할&amp;nbsp;개념들에&amp;nbsp;대해&amp;nbsp;간단히&amp;nbsp;살펴보면&amp;nbsp;다음과&amp;nbsp;같다.&amp;nbsp;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;&amp;rarr;&amp;nbsp;각&amp;nbsp;잡고&amp;nbsp;보자면&amp;nbsp;개념만으로도&amp;nbsp;살펴봐야할&amp;nbsp;내용들이&amp;nbsp;많겠지만,&amp;nbsp;이번&amp;nbsp;포스팅의&amp;nbsp;목적은&amp;nbsp;어플리케이션을&amp;nbsp;&lt;code&gt;OTel&lt;/code&gt;과&amp;nbsp;&lt;code&gt;Jaeger&lt;/code&gt;로&amp;nbsp;살펴보기&amp;nbsp;위함이니&amp;nbsp;간략히&amp;nbsp;정리했다.&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;OpenTelemetry(OTel)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;OTel&lt;/code&gt;은 API, SDK 및 도구 모음으로써, 이를 활용해 소프트웨어의 성능과 동작을 분석하는데 도움이 되는 텔레메트리 데이터(metric, log, trace)를 측정(instrument), 생성(generate), 수집(collect), 내보낼 수(export) 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;OTel Collector&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;1286&quot; data-origin-height=&quot;706&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wjvez/btsD3nC3RXd/bXiECSpNleDQ4QeUzK4ED0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wjvez/btsD3nC3RXd/bXiECSpNleDQ4QeUzK4ED0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wjvez/btsD3nC3RXd/bXiECSpNleDQ4QeUzK4ED0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwjvez%2FbtsD3nC3RXd%2FbXiECSpNleDQ4QeUzK4ED0%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;672&quot; height=&quot;369&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;1286&quot; data-origin-height=&quot;706&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;OTel&lt;/code&gt;의&amp;nbsp;핵심&amp;nbsp;구성&amp;nbsp;요소&amp;nbsp;중&amp;nbsp;하나로써,&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;code&gt;OTel&amp;nbsp;Collectors&lt;/code&gt;를&amp;nbsp;통해&amp;nbsp;텔레메트리&amp;nbsp;데이터를&amp;nbsp;수신,&amp;nbsp;처리,&amp;nbsp;내보내는&amp;nbsp;방법을&amp;nbsp;벤더사에&amp;nbsp;구애받지&amp;nbsp;않고(vendor-agnostic)&amp;nbsp;구현&lt;/span&gt;&lt;/b&gt;할&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;따라서&amp;nbsp;여러&amp;nbsp;agent/collector를&amp;nbsp;실행,&amp;nbsp;운영,&amp;nbsp;유지&amp;nbsp;관리할&amp;nbsp;필요가&amp;nbsp;없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;뒤에서 살펴볼 샘플 어플리케이션에서는 &lt;code&gt;OTel Collector&lt;/code&gt;를 통해 &lt;code&gt;Jaeger&lt;/code&gt;로 텔레메트리 데이터를 보내지만, 위 그림에서 볼 수 있듯이 &lt;code&gt;프로메테우스&lt;/code&gt;나 다른 Observability 백엔드로 데이터를 처리하고 내보낼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;분산 추적(Distributed tracing)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;분산 추적이란 분산 시스템을 통해 전달되는 데이터 요청을 관찰하는 것이다. &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;분산 추적을 통해 개발자는 마이크로서비스 전반에서 발생하는 요청 경로를 추적할 수 있다.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;Jaeger&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;분산 추적 가시성 플랫폼(Distributed tracing observability platform)&lt;i&gt;&lt;span style=&quot;color: #787774;&quot; data-token-index=&quot;1&quot;&gt; &amp;rarr; 개념만 봐서는 쉽게 와닿지 않을 수 있는데, 이후 살펴볼 Jaeger 화면을 보면 어떤 역할을 하는지 쉽게 이해할 수 있다.&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;트레이스/스팬(trace/span)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;1020&quot; data-origin-height=&quot;510&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMJrLT/btsD1bJ9T12/xpjV5VkJZv4mb1iXfPVoZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMJrLT/btsD1bJ9T12/xpjV5VkJZv4mb1iXfPVoZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMJrLT/btsD1bJ9T12/xpjV5VkJZv4mb1iXfPVoZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMJrLT%2FbtsD1bJ9T12%2FxpjV5VkJZv4mb1iXfPVoZ0%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;654&quot; height=&quot;327&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;1020&quot; data-origin-height=&quot;510&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;트레이스&lt;/code&gt;는&amp;nbsp;어플리케이션을&amp;nbsp;구성하는&amp;nbsp;서비스에서&amp;nbsp;처리하는&amp;nbsp;단일&amp;nbsp;요청의&amp;nbsp;진행&amp;nbsp;상황을&amp;nbsp;추적하는&amp;nbsp;것을&amp;nbsp;뜻한다.&amp;nbsp;&lt;code&gt;스팬&lt;/code&gt;은&amp;nbsp;&lt;code&gt;트레이스&lt;/code&gt;의&amp;nbsp;작업&amp;nbsp;단위인데,&amp;nbsp;요청이&amp;nbsp;시스템을&amp;nbsp;통과할&amp;nbsp;때&amp;nbsp;관련된&amp;nbsp;개별&amp;nbsp;서비스&amp;nbsp;또는&amp;nbsp;구성&amp;nbsp;요소가&amp;nbsp;수행하는&amp;nbsp;작업을&amp;nbsp;나타낸다.&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt; &amp;rarr; 개념과 위 그림을 함께 보면 훨씬 이해하기 쉬울 것 같다.&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;다운스트림/업스트림&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;어떤 항목이 다른 항목에 가치를 더하거나 의존하는 경우, 이를 &lt;code&gt;다운스트림&lt;/code&gt;에 해당한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;소프트웨어 의존 관계로 예를 들면, 컴포넌트 C는 컴포넌트 A와 B의 기능을 임포트하고 자신의 가치를 추가해 &lt;code&gt;다운스트림&lt;/code&gt; 컴포넌트가 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;1828&quot; data-origin-height=&quot;440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bICnXh/btsD7kLP1ZY/wAkx1fzZjNzMAdN6jpjco0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bICnXh/btsD7kLP1ZY/wAkx1fzZjNzMAdN6jpjco0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bICnXh/btsD7kLP1ZY/wAkx1fzZjNzMAdN6jpjco0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbICnXh%2FbtsD7kLP1ZY%2FwAkx1fzZjNzMAdN6jpjco0%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;623&quot; height=&quot;150&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;1828&quot; data-origin-height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마이크로서비스로 예를 들면, 서비스 A가 서비스 B를 의존하므로 &lt;code&gt;다운스트림&lt;/code&gt;이 된다. 이후에 살펴볼 어플리케이션도 이와 동일한 구성으로 되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;1034&quot; data-origin-height=&quot;892&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ERXo0/btsD7mplJrp/WX010k2FcbaWXbKSzwSVb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ERXo0/btsD7mplJrp/WX010k2FcbaWXbKSzwSVb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ERXo0/btsD7mplJrp/WX010k2FcbaWXbKSzwSVb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FERXo0%2FbtsD7mplJrp%2FWX010k2FcbaWXbKSzwSVb1%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;493&quot; height=&quot;425&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;1034&quot; data-origin-height=&quot;892&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. 어플리케이션&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;분산 추적을 위해 어플리케이션은 두 개(업스트림/다운스트림)로 나누어 구성했다. 모든 내용을 열거하기엔 분량이 많아 생략한 내용들도 있으므로, 세부 구현 내용은 &lt;u&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://github.com/seriouskang/spring-boot-in-action/tree/main/opentelemetry-setup-with-jaeger&quot; data-token-index=&quot;1&quot;&gt;github&lt;/a&gt;&lt;/span&gt;&lt;/u&gt;을 참고하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;build.gradle 설정&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706447485720&quot; class=&quot;groovy&quot; data-ke-language=&quot;groovy&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dependencyManagement {
    imports {
        mavenBom 'org.springframework.cloud:spring-cloud-dependencies:2021.0.5'
        mavenBom 'org.springframework.cloud:spring-cloud-sleuth-otel-dependencies:1.1.2'
    }
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation ('org.springframework.cloud:spring-cloud-starter-sleuth') {
        exclude group: 'org.springframework.cloud', module: 'spring-cloud-sleuth-brave'
    }
    implementation 'org.springframework.cloud:spring-cloud-sleuth-otel-autoconfigure'
    implementation 'io.opentelemetry:opentelemetry-exporter-otlp:1.23.1'
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;build.gradle&lt;/code&gt; 설정은 두 어플리케이션이 동일하다. 특이 사항이라면, &lt;code&gt;spring-cloud-sleuth&lt;/code&gt;는 &lt;code&gt;brave&lt;/code&gt;라는 분산 추적 라이브러리를 사용하는데 이를 &lt;code&gt;OTel&lt;/code&gt;로 대체하기 위해 종속성에서 제외한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 &lt;code&gt;spring-boot-starter-actuator&lt;/code&gt; 의존성의 경우 프로젝트를 구성하며 헬스 체크를 위해 넣었는데, 제외시켜도 무방하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;시퀀스 다이어그램&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;상호 작용 과정을 요약하자면 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;712&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tmztQ/btsD3J6LtDe/CddvTaRlpbUWSuD7xK0bl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tmztQ/btsD3J6LtDe/CddvTaRlpbUWSuD7xK0bl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tmztQ/btsD3J6LtDe/CddvTaRlpbUWSuD7xK0bl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtmztQ%2FbtsD3J6LtDe%2FCddvTaRlpbUWSuD7xK0bl0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;472&quot; height=&quot;342&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;712&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;다운스트림 어플리케이션&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;상품 정보를 불러올 수 있는 API(&lt;code&gt;/product/{id}&lt;/code&gt;)를 호출하면,&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706447622333&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@RestController
@RequestMapping(&quot;/product&quot;)
public class ProductController {
    ...

    @GetMapping(path = &quot;/{id}&quot;)
    public Product product(@PathVariable long id) {
        log.info(&quot;getting product and price details with product id = {}&quot;, id);
        return productRepository.findProductById(id);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;가격 정보를 불러 올 수 있는 업스트림 어플리케이션의 API를 호출해서, 데이터를 가지고 오는 형태로 되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706447643324&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class PriceClient {
    private final RestTemplate restTemplate;
    ...

    public Price price(long id) {
        log.info(&quot;fetching price details with product id = {}&quot;, id);
        String url = String.format(&quot;%s/price/%d&quot;, baseUrl, id);

        return restTemplate.getForEntity(url, Price.class)
                .getBody();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;업스트림 어플리케이션&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;가격&amp;nbsp;정보를&amp;nbsp;불러올&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;API(&lt;code&gt;/price/{id}&lt;/code&gt;)를&amp;nbsp;제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706447724670&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@RestController
@RequestMapping(&quot;/price&quot;)
public class PriceController {
    ...

    @GetMapping(path = &quot;/{id}&quot;)
    public Price price(@PathVariable long id) {
        log.info(&quot;get price details for product id = {}&quot;, id);
        return priceRepository.findPriceById(id);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;테스트 데이터&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;호출 데이터의 경우 별도의 DB를 사용하지 않고, &lt;code&gt;repository&lt;/code&gt; 빈이 생성된 이후에 특정 데이터를 메모리에 저장해서 사용하는 방식으로 구성되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;상품과 가격 데이터를 보면 상품 ID와 가격 ID가 동일한 ID를 사용하는데, 업스트림 어플리케이션에서 에러가 발생하는 케이스를 살펴보기 위해, 100005 ID의 상품은 가격 데이터가 빠져있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table id=&quot;3f246516-07c6-417e-aeb7-d0768b3d9126&quot; style=&quot;border-collapse: collapse; width: 100%; height: 104px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;상품 ID&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;상품명&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;가격 ID&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;가격&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;할인률&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;bb6b1874-0204-4672-8259-b572ff0a0158&quot; style=&quot;height: 17px;&quot;&gt;
&lt;td id=&quot;wJVp&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;100001&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;MKxm&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;apple&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;mnYN&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;100001&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;Gx]t&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;12.5&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;ZSJ}&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2.5&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;6723a9fd-b674-48fb-8761-71cad35ffe78&quot; style=&quot;height: 17px;&quot;&gt;
&lt;td id=&quot;wJVp&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;100002&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;MKxm&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;pears&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;mnYN&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;100002&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;Gx]t&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;10.5&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;ZSJ}&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2.1&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;ff2e084b-b07d-4d16-9049-63b1eb1efa65&quot; style=&quot;height: 17px;&quot;&gt;
&lt;td id=&quot;wJVp&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;100003&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;MKxm&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;banana&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;mnYN&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;100003&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;Gx]t&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;18.5&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;ZSJ}&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2.2&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;480ca160-478f-48c0-8e1e-c70139045870&quot; style=&quot;height: 17px;&quot;&gt;
&lt;td id=&quot;wJVp&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;100004&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;MKxm&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;mango&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;mnYN&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;100004&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;Gx]t&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;18.5&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;ZSJ}&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2.2&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr id=&quot;ad3c5188-9511-409f-a022-04f19248878a&quot; style=&quot;height: 17px;&quot;&gt;
&lt;td id=&quot;wJVp&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;color: #ee2323; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;100005&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;MKxm&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;color: #ee2323; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;test&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;mnYN&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;color: #ee2323; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;-&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;Gx]t&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;color: #ee2323; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;-&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td id=&quot;ZSJ}&quot; style=&quot;height: 17px;&quot;&gt;&lt;span style=&quot;color: #ee2323; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;-&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;호출 샘플&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;업스트림 어플리케이션의 포트는 18080으로 설정하고, 다운스트림 어플리케이션의 포트는 18081로 설정해두었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;정상 요청&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PZCEJ/btsD0MjkK8m/KGuHHvvDYUJfZ8kYl7N1Dk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PZCEJ/btsD0MjkK8m/KGuHHvvDYUJfZ8kYl7N1Dk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PZCEJ/btsD0MjkK8m/KGuHHvvDYUJfZ8kYl7N1Dk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPZCEJ%2FbtsD0MjkK8m%2FKGuHHvvDYUJfZ8kYl7N1Dk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;571&quot; height=&quot;85&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;188&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;에러 요청&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;766&quot; data-origin-height=&quot;166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/elvJ49/btsD6vfBeUu/1NwvGtzBMNOn354pMykqek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/elvJ49/btsD6vfBeUu/1NwvGtzBMNOn354pMykqek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/elvJ49/btsD6vfBeUu/1NwvGtzBMNOn354pMykqek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FelvJ49%2FbtsD6vfBeUu%2F1NwvGtzBMNOn354pMykqek%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;428&quot; height=&quot;93&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;766&quot; data-origin-height=&quot;166&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3. 어플리케이션 Dockerfile&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;업스트림 어플리케이션&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706447912062&quot; class=&quot;dockerfile&quot; data-ke-language=&quot;dockerfile&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM adoptopenjdk/openjdk11:alpine

ARG APP_JAR=upstream-0.0.1-SNAPSHOT.jar

COPY build/libs/${APP_JAR} /app/${APP_JAR}
WORKDIR /app
ENTRYPOINT [&quot;java&quot;, &quot;-jar&quot;, &quot;upstream-0.0.1-SNAPSHOT.jar&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;openjdk11&lt;/code&gt; 이미지를 기반으로, 빌드된 어플리케이션 jar를 특정 경로로 복사한 뒤 jar를 실행하도록 구성되어 있다. 다운스트림 어플리케이션의 구성도 jar 이름만 다르고, 동일하게 되어있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기까지 준비했다면, 컨테이너 기반으로 서비스를 호출해 볼 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;4. Spring Sleuth 구성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;Spring Sleuth&lt;/code&gt; 설정을 통해 트레이스를 &lt;code&gt;OTel Collector&lt;/code&gt;로 내보낼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;application.yml&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706448010086&quot; class=&quot;yaml&quot; data-ke-language=&quot;yaml&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  sleuth:
    otel:
      config:
        trace-id-ratio-based: 1.0
      exporter:
        otlp:
          endpoint: http://collector:4317&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;trace-id-ratio-based&lt;/code&gt; 은 수집된 &lt;code&gt;스팬&lt;/code&gt;의 샘플링 비율을 정의한 속성인데, 1.0으로 설정할 경우 모든 &lt;code&gt;스팬&lt;/code&gt;을 내보낸다는 의미이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 &lt;code&gt;OTel&lt;/code&gt; endpoint로 텔레메트리 데이터를 보내기 위한 설정이 있는데, endpoint의 경로는 이후에 살펴볼 &lt;code&gt;docker-compose&lt;/code&gt; 내 설정을 참고하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;5. OTel Collector 설정&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1706448095248&quot; class=&quot;yaml&quot; data-ke-language=&quot;yaml&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;receivers:
  otlp:
    protocols:
      grpc:
      http:

processors:
  batch:

exporters:
  jaeger:
    endpoint: jaeger-service:14250
    tls:
      insecure: true

service:
  pipelines:
    traces:
      receivers:  [ otlp ]
      processors: [ batch ]
      exporters:  [ jaeger ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;exporter&lt;/code&gt;의 경우, 예제에서 &lt;code&gt;Jaeger&lt;/code&gt;로 분산 추적을 할 예정이므로 &lt;code&gt;Jaeger&lt;/code&gt;로 설정한다. endpoint 경로는 이후에 살펴볼 &lt;code&gt;docker-compose&lt;/code&gt; 내 설정을 참고하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서비스 섹션 내 &lt;code&gt;processors&lt;/code&gt;의 &lt;code&gt;batch&lt;/code&gt; 옵션은 데이터를 더 잘 압축하고, 데이터 전송에 필요한 발신 연결 수를 줄이는데 활용된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;receiver&lt;/code&gt;는 &lt;code&gt;OTLP&lt;/code&gt;를 사용하는데, gRPC 또는 HTTP를 통해 데이터를 수신하는 것으로 보면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;6. docker-compose를 활용한 서비스 구성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서비스&amp;nbsp;기동은&amp;nbsp;docker-compose를&amp;nbsp;활용할&amp;nbsp;것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;docker-compose&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706448165006&quot; class=&quot;yaml&quot; data-ke-language=&quot;yaml&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: &quot;3.3&quot;

services:
  upstream-service:
    platform: linux/amd64
    build: upstream/
    ports:
      - &quot;18080:18080&quot;
  downstream-service:
    platform: linux/amd64
    build: downstream/
    ports:
      - &quot;18081:18081&quot;
  collector:
    image: otel/opentelemetry-collector:0.72.0
    command: [ &quot;--config=/etc/otel-collector-config.yml&quot; ]
    volumes:
      - ./otel-config.yml:/etc/otel-collector-config.yml
    ports:
      - &quot;4317:4317&quot;
    depends_on:
      - jaeger-service
  jaeger-service:
    image: jaegertracing/all-in-one:latest
    ports:
      - &quot;16686:16686&quot;
      - &quot;14250&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;upstream-service&lt;/code&gt; / &lt;code&gt;downsteam-service&lt;/code&gt;는 어플리케이션 부분으로, 특이 사항이라면 샘플 코드를 작성한 단말이 애플 Mac M1을 사용해서 &lt;code&gt;docker-compose&lt;/code&gt; 내에 &lt;code&gt;platform&lt;/code&gt;을 &lt;code&gt;linux/amd64&lt;/code&gt;로 설정해두었는데 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;다른 환경에서 테스트가 필요하다면 이 부분에 대한 수정이 필요할 수 있다!&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;collector&lt;/code&gt;는 이전에 작성한 &lt;code&gt;OTel Collector&lt;/code&gt; 설정 파일을 기반으로 &lt;code&gt;OTel Collector&lt;/code&gt;를 기동하는 부분이다. ports로 노출한 포트는 &lt;code&gt;receiver&lt;/code&gt;가 데이터를 수신할 포트로, 4317의 경우 gRPC이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;jaeger-service&lt;/code&gt;는 &lt;code&gt;Jaeger&lt;/code&gt;를 기동하는 부분으로 16886 포트는 &lt;code&gt;Jaeger UI&lt;/code&gt;이고, 14250 포트는 데이터를 수집하기 위한 포트이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;7. 서비스 기동&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서비스&amp;nbsp;기동은&amp;nbsp;어플리케이션을&amp;nbsp;빌드한&amp;nbsp;후&amp;nbsp;&lt;code&gt;docker-compse&amp;nbsp;up&lt;/code&gt;&amp;nbsp;명령어로&amp;nbsp;실행하면&amp;nbsp;된다.&amp;nbsp;&lt;a href=&quot;https://github.com/seriouskang/spring-boot-in-action/tree/main/opentelemetry-setup-with-jaeger&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github&lt;/a&gt;에&amp;nbsp;올려둔&amp;nbsp;샘플&amp;nbsp;코드에서는&amp;nbsp;&lt;code&gt;startup.sh&lt;/code&gt;&amp;nbsp;스크립트로 한번에 실행할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1706448330437&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#!/bin/sh

../gradlew downstream:build upstream:build
docker-compose up --build&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;서비스 기동 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706448364697&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker ps | grep opentelemetry
CONTAINER ID   IMAGE                                                COMMAND                  CREATED   STATUS              PORTS                                                    NAMES
...            opentelemetry-setup-with-jaeger-upstream-service     &quot;java -jar upstream-&amp;hellip;&quot;   ...       Up About a minute   0.0.0.0:18080-&amp;gt;18080/tcp                                 opentelemetry-setup-with-jaeger-upstream-service-1
...            opentelemetry-setup-with-jaeger-downstream-service   &quot;java -jar downstrea&amp;hellip;&quot;   ...       Up About a minute   0.0.0.0:18081-&amp;gt;18081/tcp                                 opentelemetry-setup-with-jaeger-downstream-service-1
...            otel/opentelemetry-collector:0.72.0                  &quot;/otelcol --config=/&amp;hellip;&quot;   ...       Up About a minute   0.0.0.0:4317-&amp;gt;4317/tcp, 55678-55679/tcp                  opentelemetry-setup-with-jaeger-collector-1
...            jaegertracing/all-in-one:latest                      &quot;/go/bin/all-in-one-&amp;hellip;&quot;   ...       Up About a minute   .., 0.0.0.0:16686-&amp;gt;16686/tcp, 0.0.0.0:50201-&amp;gt;14250/tcp   opentelemetry-setup-with-jaeger-jaeger-service-1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;8. 분산 추적&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이제 모든 준비가 끝났으니 분산 추적을 해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;요청 성공&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저 다운스트림 어플리케이션의 API&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;(ex. http://&amp;lt;server-ip&amp;gt;:18081/product/100003)&lt;/i&gt;&lt;/span&gt;를 호출하면 아래와 같은 로그를 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1706448553684&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;opentelemetry-setup-with-jaeger-downstream-service-1  | 2024-01-28 ... INFO [downstream-service,✅232b74791301ad3d39e16851314b57ba, 13a2ebe57954e543] 1 --- [io-18081-exec-5] c.example.controller.ProductController   : getting product and price details with product id = 100003
opentelemetry-setup-with-jaeger-downstream-service-1  | 2024-01-28 ... INFO [downstream-service,✅232b74791301ad3d39e16851314b57ba, 13a2ebe57954e543] 1 --- [io-18081-exec-5] c.example.repository.ProductRepository   : get product from product repo with product id = 100003
opentelemetry-setup-with-jaeger-downstream-service-1  | 2024-01-28 ... INFO [downstream-service,✅232b74791301ad3d39e16851314b57ba, 13a2ebe57954e543] 1 --- [io-18081-exec-5] com.example.api.client.PriceClient       : fetching price details with product id = 100003
opentelemetry-setup-with-jaeger-upstream-service-1    | 2024-01-28 ... INFO [upstream-service,✅232b74791301ad3d39e16851314b57ba, 7a923b69bf0d1e7f] 1 --- [io-18080-exec-3] com.example.controller.PriceController   : get price details for product id = 100003
opentelemetry-setup-with-jaeger-upstream-service-1    | 2024-01-28 ... INFO [upstream-service,✅232b74791301ad3d39e16851314b57ba, 7a923b69bf0d1e7f] 1 --- [io-18080-exec-3] com.example.repository.PriceRepository   : find price from price repo with product id = 100003&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;로그를 자세히 살펴보면 다운스트림과 업스트림 어플리케이션에서 남기는 로그에 동일한 ID(✅)가 남아있는 것을 볼 수 있는데, 이것이 &lt;code&gt;트레이스 ID&lt;/code&gt;이다. &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;이를 통해, 하나의 호출로 여러 마이크로서비스를 호출하는 환경에서 요청 흐름을 살펴볼 수 있다.&lt;/b&gt;&lt;/span&gt; 참고로 &lt;code&gt;트레이스 ID&lt;/code&gt; 옆에 있는 ID( )는 &lt;code&gt;스팬 ID&lt;/code&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 같은 정보를 확인할 수 있는 이유는 어플리케이션 의존성으로 추가했던 &lt;code&gt;Spring Cloud Sleuth&lt;/code&gt;가 API 호출 시,&amp;nbsp;&lt;code&gt;트레이스 ID&lt;/code&gt; 및 &lt;code&gt;스팬 ID&lt;/code&gt;를 HTTP 헤더에 추가해주기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;Jaeger UI&lt;/code&gt;를 통해 내용을 살펴보면, &lt;code&gt;트레이스 ID&lt;/code&gt;가 &lt;code&gt;232b747&lt;/code&gt;인 요청에 대한 정보를 확인할 수 있고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;9.png&quot; data-origin-width=&quot;2844&quot; data-origin-height=&quot;1518&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL7eSK/btsD3KYUMrV/AnpfrWGyRCLVGaKHPutf40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL7eSK/btsD3KYUMrV/AnpfrWGyRCLVGaKHPutf40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL7eSK/btsD3KYUMrV/AnpfrWGyRCLVGaKHPutf40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL7eSK%2FbtsD3KYUMrV%2FAnpfrWGyRCLVGaKHPutf40%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;2844&quot; height=&quot;1518&quot; data-filename=&quot;9.png&quot; data-origin-width=&quot;2844&quot; data-origin-height=&quot;1518&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;특정&amp;nbsp;&lt;code&gt;트레이스&amp;nbsp;ID&lt;/code&gt;에&amp;nbsp;대해서&amp;nbsp;&lt;code&gt;스팬&amp;nbsp;ID&lt;/code&gt;를&amp;nbsp;포함하여&amp;nbsp;더&amp;nbsp;많은&amp;nbsp;정보를&amp;nbsp;확인해&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;2866&quot; data-origin-height=&quot;1312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sUA7x/btsD3cVTgYj/dKUtYrnep3SE7tKtEtKIX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sUA7x/btsD3cVTgYj/dKUtYrnep3SE7tKtEtKIX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sUA7x/btsD3cVTgYj/dKUtYrnep3SE7tKtEtKIX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsUA7x%2FbtsD3cVTgYj%2FdKUtYrnep3SE7tKtEtKIX0%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;2866&quot; height=&quot;1312&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;2866&quot; data-origin-height=&quot;1312&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;요청 실패&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;성공 요청에 대한 트레이스 모니터링도 해보았으니, 실패 요청에 대한 모니터링도 해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;상품 ID가 &lt;code&gt;100005&lt;/code&gt;로 상품 정보를 요청할 경우, 가격 정보가 없어 업스트림 어플리케이션에서 &lt;code&gt;404&lt;/code&gt; 에러를 내도록 구성 되어있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;11.png&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;178&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHrU8z/btsD3KEADg0/zAB1YVFvw64r2krgOc8aM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHrU8z/btsD3KEADg0/zAB1YVFvw64r2krgOc8aM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHrU8z/btsD3KEADg0/zAB1YVFvw64r2krgOc8aM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHrU8z%2FbtsD3KEADg0%2FzAB1YVFvw64r2krgOc8aM1%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;529&quot; height=&quot;120&quot; data-filename=&quot;11.png&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;178&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이를&amp;nbsp;&lt;code&gt;Jaeger&amp;nbsp;UI&lt;/code&gt;에서&amp;nbsp;살펴보면,&amp;nbsp;빨간색&amp;nbsp;표시가&amp;nbsp;뜨면서&amp;nbsp;에러가&amp;nbsp;발생했음을&amp;nbsp;알&amp;nbsp;수&amp;nbsp;있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;2136&quot; data-origin-height=&quot;1066&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rkncJ/btsD4rLwEtq/iLUZ1hURL9qu5ZdWtY31l0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rkncJ/btsD4rLwEtq/iLUZ1hURL9qu5ZdWtY31l0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rkncJ/btsD4rLwEtq/iLUZ1hURL9qu5ZdWtY31l0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrkncJ%2FbtsD4rLwEtq%2FiLUZ1hURL9qu5ZdWtY31l0%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;2136&quot; height=&quot;1066&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;2136&quot; data-origin-height=&quot;1066&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;스팬 정보에서 HTTP status code도 확인 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;13.png&quot; data-origin-width=&quot;2864&quot; data-origin-height=&quot;1826&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgHtbQ/btsD0LY3qcI/pkJbGMRPYZ8OwFb2FBjCek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgHtbQ/btsD0LY3qcI/pkJbGMRPYZ8OwFb2FBjCek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgHtbQ/btsD0LY3qcI/pkJbGMRPYZ8OwFb2FBjCek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgHtbQ%2FbtsD0LY3qcI%2FpkJbGMRPYZ8OwFb2FBjCek%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;2864&quot; height=&quot;1826&quot; data-filename=&quot;13.png&quot; data-origin-width=&quot;2864&quot; data-origin-height=&quot;1826&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;9. 정리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;어플리케이션 개발부터 &lt;code&gt;OTel&lt;/code&gt;, &lt;code&gt;Jaeger&lt;/code&gt;를 통한 분산 추적까지 해보았는데, 하나의 포스팅에 담기에는 꽤나 많은 양이었던 것 같다. 분량상 설명이 생략된 부분도 있긴 하지만, 그래도 나처럼 어플리케이션을 띄워보면서 이해하는걸 선호하는 분들에게 어떤 식으로든 도움이 되었으면 좋겠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;많은 내용들이 있었지만, 그 중에서 개인적으로 중요하다고 생각되는 트레이스 데이터의 흐름을 요약하는 걸로 이번 포스팅을 마치겠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;트레이스 데이터 흐름 요약&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706448979567&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. 유저가 `다운스트림` 어플리케이션의 상품 조회 API를 호출
2. `다운스트림`/`업스트림` 어플리케이션에서 `Collector`로 트레이스 데이터 전송(4317 port)
3. `Collector`는 `Jaeger` 엔드포인트를 통해 트레이스 데이터를 `Jaeger` 백엔드로 전송(14250 port)
4. 로그 및 `Jaeger` UI를 통해 분산 추적&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;샘플 코드  &lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://github.com/seriouskang/spring-boot-in-action/tree/main/opentelemetry-setup-with-jaeger&quot;&gt;https://github.com/seriouskang/spring-boot-in-action/tree/main/opentelemetry-setup-with-jaeger&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;참고 자료  &amp;zwj;♂️&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://www.baeldung.com/spring-boot-opentelemetry-setup&quot;&gt;https://www.baeldung.com/spring-boot-opentelemetry-setup&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://reflectoring.io/upstream-downstream/&quot;&gt;https://reflectoring.io/upstream-downstream/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://www.jaegertracing.io/&quot;&gt;https://www.jaegertracing.io/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://aws.amazon.com/ko/what-is/distributed-tracing/&quot;&gt;https://aws.amazon.com/ko/what-is/distributed-tracing/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://opentelemetry.io/&quot;&gt;https://opentelemetry.io/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://hackage.haskell.org/package/hs-opentelemetry-sdk-0.0.3.6/docs/OpenTelemetry-Trace.html&quot;&gt;https://hackage.haskell.org/package/hs-opentelemetry-sdk-0.0.3.6/docs/OpenTelemetry-Trace.html&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>observability</category>
      <category>jaeger</category>
      <category>o11y</category>
      <category>observability</category>
      <category>opentelemetry</category>
      <category>otel</category>
      <category>otel collector</category>
      <category>span id</category>
      <category>spring sleuth</category>
      <category>Trace</category>
      <category>trace id</category>
      <author>시리어스강</author>
      <guid isPermaLink="true">https://seriouskang.tistory.com/13</guid>
      <comments>https://seriouskang.tistory.com/13#entry13comment</comments>
      <pubDate>Sun, 28 Jan 2024 22:39:56 +0900</pubDate>
    </item>
    <item>
      <title>[회고] 2023년 회고와 2024년의 목표</title>
      <link>https://seriouskang.tistory.com/12</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지난 해를 돌이켜보며 회고를 해보자라는 계획은 예전부터 해왔지만, 조금 귀찮기도 했고 불편한 상황들은 외면하고 싶은 심정도 있어 각잡고 해본 적은 없었다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그런데 요즘 가장 즐겨보는 &lt;a href=&quot;https://www.youtube.com/watch?v=f48hQSZY_hc&amp;amp;t=491s&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;유튜버의 영상&lt;/a&gt;을 보고 생각이 바뀌었다. 영상을 요약하자면 &amp;ldquo;중학교 때까지 성적이 좋지 않던 유도 선수 이원희가 &lt;b&gt;성적을 높일 수 있었던 계기가 본인시합을 돌려보며 자신에 대해서 파악한 것&lt;/b&gt;&amp;rdquo;이라고 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1872&quot; data-origin-height=&quot;1028&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4ZVEz/btsC3Y5CXG1/m1RiGXgPAKzyGnIiUVKIIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4ZVEz/btsC3Y5CXG1/m1RiGXgPAKzyGnIiUVKIIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4ZVEz/btsC3Y5CXG1/m1RiGXgPAKzyGnIiUVKIIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4ZVEz%2FbtsC3Y5CXG1%2Fm1RiGXgPAKzyGnIiUVKIIK%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;566&quot; height=&quot;311&quot; data-origin-width=&quot;1872&quot; data-origin-height=&quot;1028&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;누군가는 회사에선 시키는 일만하고 돈만 벌면 된다고 하지만, &lt;b&gt;나는 회사에 있는 동안 즐거웠으면 좋겠고 그건 보통 맡은 일을 기술적으로 잘 해냈을 때 만족감이 높았다. &lt;/b&gt;결국 내가 발전하고 행복하기 위해 번거롭더라도 2023년을 돌아보고, 2024년에는 뭘할지 정해보려고 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;회고와 목표 요약&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;2023년에는&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2022년에 이어서 유지보수하기 좋은 코드를 작성하기 위한 지식을 실무에서 적극 활용했다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;컴포트존에서 벗어나기 위한 선택&lt;/b&gt;을 했고, 회사에서의 역할이 백엔드 개발자에서 SRE 개발자로 바뀌었다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그에 따라 쿠버네티스와 관련된 업무를 담당하게 되었다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;2024년에는&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;정기적으로 프로필을 정리해 내 상황에 대한 점검을 해보려고 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;쿠버네티스, 퍼블릭 클라우드 그리고 대규모 트래픽 처리와 관련된 학습을 할 것이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;오프라인 커뮤니티 모임과 행사에 참여하여 인사이트를 얻어보려고 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;고민을 통해 해결할 수 있는 문제가 아닌 상황에서는 &amp;ldquo;그냥 그렇구나&amp;rdquo;라는 마음가짐을 가질 것이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;2023년 회고&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;직장 생활을 하며 무난하게 보낸 해는 거의 없었지만, 2023년에는 부서가 바뀌고 업무도 조정 되면서 유독 많은 일들이 있었다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;유지보수하기 좋은 코드를 작성하기 위한 지식을 실무에 적용&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;책과 강의로 학습했던 &lt;code&gt;TDD&lt;/code&gt;, &lt;code&gt;DDD&lt;/code&gt;, &lt;code&gt;클린 아키텍처&lt;/code&gt; 등을 22년부터 23년까지 실무에 적용하며, &lt;b&gt;유지보수하기 좋은 코드를 작성하는데 필요한 기술들을 적극적으로 활용할 수 있는 시간&lt;/b&gt;이었다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 NEXTSTEP의 &lt;a href=&quot;https://edu.nextstep.camp/c/8fWRxNWU/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;TDD, 클린 코드 with Java&lt;/a&gt; 강의를 통해 레거시 코드를 어떻게 리팩토링하는지, 깔끔한 코드를 작성하기 위해서는 어떻게 하면 좋을지 코드 리뷰 기반으로 배울 수 있었다. 수업이 있는 8주간 퇴근 이후의 개인 시간과 주말을 대부분 갈아넣었는데, 힘들기보다는 개발에 몰입했던 과정이 정말 즐거웠다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;조금 아쉬운 점이라면 현재는 롤이 변경되어 개발과는 조금 멀어졌으나, 내 베이스는 백엔드 개발이라고 생각하고 다시 개발자의 역할을 해야하는 상황이 온다면 기쁜 마음으로 수행할 것이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;백엔드 개발에서 SRE로&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기존에 있던 부서가 다른 부서로 통합되며, &lt;b&gt;업무가 백엔드 개발에서 SRE로 변경&lt;/b&gt;되었다. 2023년의 주 역할은 부서 내 각 파트의 어플리케이션을 컨테이너 오케스트레이션 플랫폼 위에 얹기 위해 필요한 일들을 수행했다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예컨대 CI/CD 환경을 구성한다거나, 쿠버네티스 매니페스트 파일을 작성하거나, 컨테이너 오케스트레이션 플랫폼 업그레이드 등을 진행했다. 더불어 사내 DR 시스템을 퍼블릭 클라우드로 이관하는 준비를 하고 있어 그에 대한 PoC도 수행했다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2023년에는 기존에 하던 업무와 신규 업무를 병행해서 100% 역할이 변경된건 아니지만, 이전부터 일을 해오던 동료 분을 봤을 때는 어플리케이션 개발 외에 필요한 것들은 다 처리하는 것 같다  &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;컴포트존에서 벗어나기&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3211&quot; data-origin-height=&quot;1875&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oLxkv/btsC4va4tiO/dUcg1R7UOn5GyIF2G4gELk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oLxkv/btsC4va4tiO/dUcg1R7UOn5GyIF2G4gELk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oLxkv/btsC4va4tiO/dUcg1R7UOn5GyIF2G4gELk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoLxkv%2FbtsC4va4tiO%2FdUcg1R7UOn5GyIF2G4gELk%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;548&quot; height=&quot;320&quot; data-origin-width=&quot;3211&quot; data-origin-height=&quot;1875&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;거의 이직에 가까운 역할 변화가 있었는데, 부서가 통합되며 몇가지 선택할 수 있는 옵션 중 하나였기 때문에 결국 내가 선택한 일이다. 그런 선택을 한 이유는 기존에 내가 맡은 업무에서 이미 많은 부분을 리팩토링했고 업무 자체도 익숙해진 상태라, &lt;b&gt;컴포트존에서 벗어나 새로운 것들을 배워보자&lt;/b&gt;라는&amp;nbsp;생각이었다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;결론적으로는 컴포트존에서 벗어나긴 했지만, 너무 많이 벗어났던 건지 배우는 건 많지만 그만큼 스트레스를 받고 있는건 사실이다  &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기존에는 요구사항을 받아 어플리케이션을 개발하고 &lt;code&gt;CI&lt;/code&gt;만 해두면 그 이후의 과정은 다른 분들이 맡아주셨지만, 이제는 반대로 컨테이너 오케스트레이션과 더불어 웹 서버/로드 밸런서 설정, DNS, 인증서, 서버 계정별 세부 권한 설정 등 이전에는 크게 염두하지 않았던 운영에 필요한 지식이 필요하게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;최근 &lt;a href=&quot;https://brunch.co.kr/@cleancode/70&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;백명석님의 글&lt;/a&gt;에서 배우는 것과 성과에 대한 내용을 보게 되었는데, 내가 처한 상황이랑 비슷해 많은 공감과 힘을 얻었다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1874&quot; data-origin-height=&quot;1198&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4v8a1/btsC4HoVHLQ/1M1XZCDqongnaJ6KhGWxa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4v8a1/btsC4HoVHLQ/1M1XZCDqongnaJ6KhGWxa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4v8a1/btsC4HoVHLQ/1M1XZCDqongnaJ6KhGWxa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4v8a1%2FbtsC4HoVHLQ%2F1M1XZCDqongnaJ6KhGWxa0%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;577&quot; height=&quot;369&quot; data-origin-width=&quot;1874&quot; data-origin-height=&quot;1198&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;요약하자면, &amp;ldquo;새로운 기술을 배울 때는 이전에 익숙한 기술을 사용할 때보다 성과가 떨어질 수 있는데(고통의 계곡), &lt;b&gt;그 상황에서 빠져나오면 기하급수적으로 성장할 수 있다&lt;/b&gt;&amp;rdquo;는 것이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;더 큰 성장을 하기 위해 선택한 길이기 때문에, 어느 정도의 압박은 있더라도 고통의 계곡이 새로운 컴포트존이 될 수 있도록 노력해보려고 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;쿠버네티스 학습&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너 기반 서비스가 주된 역할 중에 하나이기 때문에, 쿠버네티스에 대한 학습을 했다. 자격증 자체는 실무에서 크게 도움이 되지 않는다는 것은 알고 있지만, 데드라인을 정해 전반적인 개요를 살펴보기엔 자격증을 따는 것&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;(== 사비를 쓰는 것)&lt;/i&gt;&lt;/span&gt;이 괜찮은 방법이라 생각해서 &lt;code&gt;CKA&lt;/code&gt;도 취득했다  &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1934&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceLEHA/btsC9nJzZcK/0LHdWGJznR712CrWBVAVu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceLEHA/btsC9nJzZcK/0LHdWGJznR712CrWBVAVu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceLEHA/btsC9nJzZcK/0LHdWGJznR712CrWBVAVu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceLEHA%2FbtsC9nJzZcK%2F0LHdWGJznR712CrWBVAVu1%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;655&quot; height=&quot;83&quot; data-origin-width=&quot;1934&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;퍼블릭 클라우드 PoC를 수행하며 관리형 쿠버네티스 서비스도 사용해보았기 때문에, 아래의 일 정도는 혼자 수행할 수 있게 되었다 &lt;span style=&quot;color: #787774;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;- 백엔드 어플리케이션 개발 
- CI 환경 구축: 어플리케이션 빌드 및 이미지 생성
- 온프레미스 혹은 클라우드 환경에 쿠버네티스 사용 환경 구축 ✅
- 쿠버네티스 오브젝트 생성을 위한 매니페스트 작성 ✅
- GitOps 방식을 통한 CD 환경 구축 ✅&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;블로그 시작&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;구글링을 하다보면 눈에 띄는 블로거들이 있고 나도 그런 분들처럼 멋진 개발자/엔지니어가 되고 싶다는 생각에, 2023년 3월을 시작으로 블로그를 시작했다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;잘한 점이라면 블로그를 시작할 때 평균 한달에 하나라도 포스팅 하자라는 목표를 지켰고, 아쉬운 점이라면 포스팅할 주제들은 정말 많았는데&lt;i&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(실무에서의 이슈, 교육, 읽은 책 등)&lt;/span&gt;&lt;/i&gt; 조금씩 미루다보니 결국 적다만 글들이 많이 쌓여버렸다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;한해동안 경험으로 배운건, &lt;b&gt;나중에 하자는 보통 안하게 되더라. 생각날 때 그냥 하자.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;2024년 목표&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이루기 어려운 목표보다 충분히 실천할 수 있는 정도의 목표를 세워보았다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;정기적으로 프로필 정리하기&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckotZ6/btsC4EFLArF/iAJdayKaxWOebmNqDkLeMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckotZ6/btsC4EFLArF/iAJdayKaxWOebmNqDkLeMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckotZ6/btsC4EFLArF/iAJdayKaxWOebmNqDkLeMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckotZ6%2FbtsC4EFLArF%2FiAJdayKaxWOebmNqDkLeMk%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;498&quot; height=&quot;212&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;회고를 작성한 이유와 동일하게, &lt;b&gt;앞으로 내가 더 잘하기 위해&lt;/b&gt; 프로필도 정기적으로 정리해두려고 한다. 당장의 이직이 목적이 아니라, 내가 어떤 길을 걸어왔는지 봐야 앞으로 가야할 길을 올바르게 정할 수 있을 것이라 생각한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;귀찮고 번거로운 일들을 부채로 쌓다보면 결국 더 큰 이자로 돌아오게 되니까, 이제라도 원금도 조금씩 갚을 때다.&amp;nbsp;못해도 &lt;b&gt;분기에 한번은 업데이트&lt;/b&gt;하자.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;쿠버네티스 심화 학습&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2024년에는 상용 컨테이너 오케스트레이션 플랫폼(&lt;code&gt;OCP&lt;/code&gt;)과 함께 쿠버네티스를 통해 서비스를 운영할 계획이라고 한다. 단순히 쿠버네티스를 사용하는 정도를 넘어 air gap 환경에서 쿠버네티스 사용 환경 구축부터 운영 상황에서의 트러블 슈팅까지 큰 이슈 없이 잘 해낼 수 있도록, &lt;b&gt;쿠버네티스의 심연을 들여다보기 위해 노력&lt;/b&gt;할 것이다  &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;추가로 지난 사이버 먼데이에 구매한 &lt;code&gt;CKAD&lt;/code&gt;도 취득해야지&amp;hellip;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;퍼블릭 클라우드 학습&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사내의 DR 시스템을 퍼블릭 클라우드를 활용해 구축할 계획이 있기 때문에, &lt;code&gt;CSP&lt;/code&gt;가 정해지진 않았지만 널리 사용되는 &lt;code&gt;AWS&lt;/code&gt;에 대한 학습을 하려고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지난 PoC를 통해 경험해본 &lt;code&gt;AWS&lt;/code&gt;는 생각보다 유저가 직접 핸들링해야 할 부분이 많았고&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;(구성도도 자동으로 그려주는게 아니었다&amp;hellip;)&lt;/i&gt;&lt;/span&gt;, 익숙하다면 키워드만 들어도 이해할 수 있는 서비스들도 익숙하지 않으면 전혀 감도 안오는 것들이 부지기수이기 때문에 &lt;code&gt;MSP&lt;/code&gt;든 보안/인프라 부서든 원활히 논의를 할 수 있을 정도의 지식은 갖추고 있어야 할 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;code&gt;IaC&lt;/code&gt;도 까지 학습할 수 있으면 좋겠지만, 그건 일이 어떻게 진행되는지에 따라 정하면 될 것 같다.&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;대규모 트래픽 처리를 위한 학습&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;올해 부서 계획에 &lt;code&gt;kafka&lt;/code&gt;를 도입하는 것과 이전에 내가 개발하고 유지보수했던 어플리케이션을 고객사 설치형이 아니라 서비스 형태로 본격적으로 제공할 예정이라 대규모 트래픽 처리에 대한 니즈가 있을 것이라 생각한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;물론 역할이 변경되면서 개발보단 그 외적인 부분에 대한 업무를 수행하게 되겠지만, 그래도 논의를 하거나 의사결정을 해야하는 상황에서 목소리를 내고 싶기 때문에 이와 관련된 학습을 하려고 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지금 당장 구체적인 계획을 세우진 못했지만, 최소 &amp;ldquo;가상 면접 사례로 배우는 대규모 시스템 설계 기초 1, 2&amp;rdquo; 정도는 완독해서 내걸로 만들어야지.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;오프라인 커뮤니티 모임 / 행사 참여&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;레퍼런스는 부족한데 선택권이 여러 개인 상황에서 취사선택을 어떻게 할지에 대한 건 늘 고민이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예를 들어 온프레미스 환경에 쿠버네티스을 구축하는 것만 하더라도, 관리형 서비스를 사용할지 직접 구축할지 정해야 한다. 그리고 직접 설치한다면 어떤 OS에(&lt;code&gt;CoreOS&lt;/code&gt;, &lt;code&gt;RHEL&lt;/code&gt;&amp;hellip;) 어떻게 쿠버네티스를 구축할지(&lt;code&gt;k3s&lt;/code&gt;, &lt;code&gt;k8s&lt;/code&gt;&amp;hellip;)에 대한 부분도 정해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;구현을 하고 이후에 리팩토링을 할 수 있는 어플리케이션과 달리 어플리케이션이 기동되는 환경의 경우, 구축이 되고 서비스가 시작되는 순간 달리는 기차가 되어버리기 때문에 바퀴를 갈아끼는건 생각만 해도 골치가 아프다  &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러므로 &lt;b&gt;비슷한 일들을 하시는 분들을 만나서 힌트도 얻고, 최근 동향은 어떻게 되는지도 접해봐야지.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;border-radius: 5px; padding: 0.6em 0.6em; background: #f1f1f3; font-weight: bold; font-family: 'Nanum Gothic';&quot;&gt;&amp;ldquo;그냥 그렇구나&amp;rdquo;라는 마인드셋&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;944&quot; data-origin-height=&quot;918&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/53JXY/btsC2x1qPAm/6a8VBaf0VjygoarG1LQND0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/53JXY/btsC2x1qPAm/6a8VBaf0VjygoarG1LQND0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/53JXY/btsC2x1qPAm/6a8VBaf0VjygoarG1LQND0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F53JXY%2FbtsC2x1qPAm%2F6a8VBaf0VjygoarG1LQND0%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;468&quot; height=&quot;455&quot; data-origin-width=&quot;944&quot; data-origin-height=&quot;918&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;어느날&amp;nbsp;&lt;a href=&quot;https://www.youtube.com/watch?v=57aZV6Q9Uak&amp;amp;list=LL&amp;amp;index=38&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;자존감 높은 사람이 절대 하지 않는 한 가지&lt;/a&gt;라는 쇼츠를 보게 되었다. 내용은 &lt;b&gt;자존감이 높은 사람은 무슨 일이 있을 때 부정적인 생각 없이 &amp;ldquo;그냥 그렇구나&amp;rdquo;라고 하고 끝난다는 것&lt;/b&gt;인데, 내가 가져야할 마음가짐이라 생각해 기억해두고 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기존 부서도 없어지고 컴포트존에서 꽤나 멀리 떨어져오면서 조금은 불안하고 걱정이 되기는 하지만, 그것들이 해결해줄 수 있는 것들은 거의 없다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;오히려 걱정과 고민 때문에 스트레스를 받아 루틴이 깨지고 이게 다시 불안으로 이어지는 악순환이 반복될 뿐이다. &lt;b&gt;고민이 아무런 도움이 안되는 상황에서는 &amp;ldquo;왜 이렇게 되었을까&amp;rdquo;보다는 &amp;ldquo;그냥 그렇구나&amp;rdquo;라는 마인드셋을 가져야지.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;</description>
      <category>회고 및 단상</category>
      <category>2023년</category>
      <category>2023년 회고</category>
      <category>2024년</category>
      <category>2024년 목표</category>
      <category>목표</category>
      <category>회고</category>
      <author>시리어스강</author>
      <guid isPermaLink="true">https://seriouskang.tistory.com/12</guid>
      <comments>https://seriouskang.tistory.com/12#entry12comment</comments>
      <pubDate>Sat, 6 Jan 2024 11:19:16 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 어플리케이션 종료 시 들어온 요청은 처리하고 마치기(graceful shutdown)</title>
      <link>https://seriouskang.tistory.com/11</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;최근에 클라이언트 요청이 처리되는 와중에 어플리케이션이 종료될 경우, 그 요청은 어떻게 되는지에 대한 문의가 와서 겸사겸사 &lt;code&gt;graceful&amp;nbsp;shutdown&lt;/code&gt;에&amp;nbsp;대해서&amp;nbsp;포스팅을 해보려고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;619&quot; data-origin-height=&quot;571&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dauyyN/btszNRm1jF1/5nKLa4goGdR77HyGyG8Wx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dauyyN/btszNRm1jF1/5nKLa4goGdR77HyGyG8Wx0/img.png&quot; data-alt=&quot;ㅁㅊㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dauyyN/btszNRm1jF1/5nKLa4goGdR77HyGyG8Wx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdauyyN%2FbtszNRm1jF1%2F5nKLa4goGdR77HyGyG8Wx0%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;396&quot; height=&quot;571&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;619&quot; data-origin-height=&quot;571&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ㅁㅊㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;0. graceful shutdown이란?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서론에서 &lt;code&gt;graceful shutdown&lt;/code&gt;이라는 표현을 했는데, 이에 대해서 간략히 설명하자면 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;graceful shutdown&lt;/code&gt;이란 질서정연한 방식으로 어플리케이션을 종료하는 절차를 뜻한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다시 말해 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;어플리케이션이 완전히 종료되기 전에 진행 중인 모든 작업을 완료하고, 리소스는 적절하게 해제하고, 데이터 무결성이 유지되도록 필요한 조치를 취하는 행위&lt;/b&gt;&lt;/span&gt;를 뜻한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;즉, &lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;&amp;ldquo;클라이언트의 요청을 처리하는 와중에 어플리케이션을 종료시켰을 때 요청을 잘 처리하고 종료하는가?&amp;rdquo;를 다른 말로 표현하자면 &amp;ldquo;어플리케이션이 graceful shutdown을 지원하는가?&amp;rdquo;&lt;/b&gt;가 되는 것&lt;/span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. graceful shutdown 활성화&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;Spring Boot 2.3&lt;/code&gt;부터 &lt;code&gt;graceful shutdown&lt;/code&gt;을 지원하고, 이를 활성화하기 위해서는 아래에 해당하는 프로퍼티를 설정한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;참고로 해당 프로퍼티를 설정하지 않을 경우 기본 값으로 &lt;code&gt;immediate&lt;/code&gt;가 세팅되는데, 이는 요청 여부와 상관 없이 서버를 즉시 종료한다는 뜻이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1699181113908&quot; class=&quot;yaml&quot; data-ke-language=&quot;yaml&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;server:
  shutdown: graceful&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. 샘플 프로젝트 준비&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;요청에&amp;nbsp;대한&amp;nbsp;처리&amp;nbsp;시간을&amp;nbsp;조정하며&amp;nbsp;테스트를&amp;nbsp;진행할&amp;nbsp;예정이기&amp;nbsp;때문에&amp;nbsp;&lt;code&gt;Controller&lt;/code&gt;와&amp;nbsp;&lt;code&gt;graceful&amp;nbsp;shutdown&lt;/code&gt;와 관련된 프로퍼티를 위해 &lt;code&gt;application.yml&lt;/code&gt;&amp;nbsp;파일을&amp;nbsp;추가하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;538&quot; data-origin-height=&quot;532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PSLWT/btszLrbiOWr/pE9n5nLjRctSU3ovN3TSZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PSLWT/btszLrbiOWr/pE9n5nLjRctSU3ovN3TSZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PSLWT/btszLrbiOWr/pE9n5nLjRctSU3ovN3TSZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPSLWT%2FbtszLrbiOWr%2FpE9n5nLjRctSU3ovN3TSZK%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;253&quot; height=&quot;250&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;538&quot; data-origin-height=&quot;532&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Controller&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;Controller&lt;/code&gt;는&amp;nbsp;아래와&amp;nbsp;같이&amp;nbsp;작성했는데,&amp;nbsp;&lt;code&gt;graceful&amp;nbsp;shutdown&lt;/code&gt;이&amp;nbsp;잘&amp;nbsp;되는지&amp;nbsp;확인하기&amp;nbsp;위해&amp;nbsp;요청을&amp;nbsp;처리하는데&amp;nbsp;드는&amp;nbsp;시간을&amp;nbsp;일부러&amp;nbsp;늘렸다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1699181217720&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
@RestController
public class SampleController {
    @GetMapping(&quot;/foo&quot;)
    public String foo() throws InterruptedException {
        log.info(&quot;get request&quot;);
        bar();

        return &quot;success&quot;;
    }

    private void bar() throws InterruptedException {
        Thread.sleep(60000);
        log.info(&quot;end bar method&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3. graceful shutdown 활성화 전&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;graceful&amp;nbsp;shutdown&lt;/code&gt;을&amp;nbsp;활성화&amp;nbsp;하기&amp;nbsp;전에&amp;nbsp;테스트를&amp;nbsp;수행한&amp;nbsp;결과는&amp;nbsp;다음과&amp;nbsp;같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;정상 테스트&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;요청 처리에 드는 시간을 10초로 변경하여 테스트를 수행했고 어플리케이션 프로세스를 죽이지 않았으므로, 요청을 보내고 10초 뒤에 응답을 받았다는걸 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;2138&quot; data-origin-height=&quot;98&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dxcux2/btszLs2krj2/QZYSl07ZFg9lkxhUPQo7K1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dxcux2/btszLs2krj2/QZYSl07ZFg9lkxhUPQo7K1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dxcux2/btszLs2krj2/QZYSl07ZFg9lkxhUPQo7K1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdxcux2%2FbtszLs2krj2%2FQZYSl07ZFg9lkxhUPQo7K1%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;2138&quot; height=&quot;98&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;2138&quot; data-origin-height=&quot;98&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;56&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cg2bit/btszK48s0sl/FjFSjHzK1o6y45BIKKn0e1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cg2bit/btszK48s0sl/FjFSjHzK1o6y45BIKKn0e1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cg2bit/btszK48s0sl/FjFSjHzK1o6y45BIKKn0e1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcg2bit%2FbtszK48s0sl%2FFjFSjHzK1o6y45BIKKn0e1%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;344&quot; height=&quot;40&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;56&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;요청 처리 중 process kill&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;요청을 처리하는 와중에 프로세스를 죽였을 경우, 응답을 받기 전에 어플리케이션이 종료되어버린다. bar 메소드와 관련된 로그도 남지 않았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;2596&quot; data-origin-height=&quot;218&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lyYBg/btszNSMYge1/jwlH7lhIoYJwfEopsrwqyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lyYBg/btszNSMYge1/jwlH7lhIoYJwfEopsrwqyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lyYBg/btszNSMYge1/jwlH7lhIoYJwfEopsrwqyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlyYBg%2FbtszNSMYge1%2FjwlH7lhIoYJwfEopsrwqyK%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;2596&quot; height=&quot;218&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;2596&quot; data-origin-height=&quot;218&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;468&quot; data-origin-height=&quot;240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbs6sA/btszKe4PD9C/dddDfvafQVdHIhQiSw0ZmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbs6sA/btszKe4PD9C/dddDfvafQVdHIhQiSw0ZmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbs6sA/btszKe4PD9C/dddDfvafQVdHIhQiSw0ZmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdbs6sA%2FbtszKe4PD9C%2FdddDfvafQVdHIhQiSw0ZmK%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;262&quot; height=&quot;134&quot; data-filename=&quot;6.png&quot; data-origin-width=&quot;468&quot; data-origin-height=&quot;240&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;4. graceful shutdown 활성화 후&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;정상 테스트&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;프로세스를&amp;nbsp;죽이지&amp;nbsp;않을&amp;nbsp;경우에는&amp;nbsp;&lt;code&gt;graceful&amp;nbsp;shutdown&lt;/code&gt;을&amp;nbsp;활성화하기&amp;nbsp;전과&amp;nbsp;동일하게&amp;nbsp;요청/응답이&amp;nbsp;잘&amp;nbsp;이뤄짐을&amp;nbsp;알&amp;nbsp;수&amp;nbsp;있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;1620&quot; data-origin-height=&quot;90&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dVHHLR/btszKEPILIw/3WPmFK6uoY2grVMxbdEFvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dVHHLR/btszKEPILIw/3WPmFK6uoY2grVMxbdEFvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dVHHLR/btszKEPILIw/3WPmFK6uoY2grVMxbdEFvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdVHHLR%2FbtszKEPILIw%2F3WPmFK6uoY2grVMxbdEFvK%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;1620&quot; height=&quot;90&quot; data-filename=&quot;7.png&quot; data-origin-width=&quot;1620&quot; data-origin-height=&quot;90&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;58&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYJgPM/btszH49tGTV/r5RrC9GokgaXrHOJJJ2Xtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYJgPM/btszH49tGTV/r5RrC9GokgaXrHOJJJ2Xtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYJgPM/btszH49tGTV/r5RrC9GokgaXrHOJJJ2Xtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYJgPM%2FbtszH49tGTV%2Fr5RrC9GokgaXrHOJJJ2Xtk%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;306&quot; height=&quot;37&quot; data-filename=&quot;8.png&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;58&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;요청 처리 중 process kill&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;요청을&amp;nbsp;보낸&amp;nbsp;뒤에&amp;nbsp;프로세스를&amp;nbsp;죽일&amp;nbsp;경우,&amp;nbsp;&lt;code&gt;graceful&amp;nbsp;shutdown&lt;/code&gt;이&amp;nbsp;시작되었다는&amp;nbsp;로그와&amp;nbsp;함께&amp;nbsp;요청이&amp;nbsp;정상처리&amp;nbsp;되고&amp;nbsp;&lt;code&gt;graceful&amp;nbsp;shutdown&lt;/code&gt;이&amp;nbsp;완료되었다는&amp;nbsp;로그를&amp;nbsp;남긴다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;9.png&quot; data-origin-width=&quot;2586&quot; data-origin-height=&quot;336&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nzSEd/btszJJKLU7p/cjGXwf6B4aGQkUv91cPFh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nzSEd/btszJJKLU7p/cjGXwf6B4aGQkUv91cPFh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nzSEd/btszJJKLU7p/cjGXwf6B4aGQkUv91cPFh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnzSEd%2FbtszJJKLU7p%2FcjGXwf6B4aGQkUv91cPFh1%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;2586&quot; height=&quot;336&quot; data-filename=&quot;9.png&quot; data-origin-width=&quot;2586&quot; data-origin-height=&quot;336&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;438&quot; data-origin-height=&quot;200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8PETk/btszLnfKO9U/8de2BP9s1TSoPq95fFAJD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8PETk/btszLnfKO9U/8de2BP9s1TSoPq95fFAJD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8PETk/btszLnfKO9U/8de2BP9s1TSoPq95fFAJD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8PETk%2FbtszLnfKO9U%2F8de2BP9s1TSoPq95fFAJD1%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;247&quot; height=&quot;113&quot; data-filename=&quot;10.png&quot; data-origin-width=&quot;438&quot; data-origin-height=&quot;200&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;graceful shutdown 중 요청&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;graceful shutdown&lt;/code&gt;이 되고 있을 때 요청이 들어오면 어떻게 될까? &lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;정답은 서버에서 요청을 받아주지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;11.gif&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;304&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FJ7DW/btszKIdBNQL/psY9GbfEK9urVHUjz7ja9K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FJ7DW/btszKIdBNQL/psY9GbfEK9urVHUjz7ja9K/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FJ7DW/btszKIdBNQL/psY9GbfEK9urVHUjz7ja9K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/FJ7DW/btszKIdBNQL/psY9GbfEK9urVHUjz7ja9K/img.gif&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;556&quot; height=&quot;304&quot; data-filename=&quot;11.gif&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;304&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;5. shutdown timeout&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;timeout&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;graceful shutdown&lt;/code&gt;을 활성화했다고 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;요청을 처리하기 위해 무한히 기다리는 것은 아니다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아래의 예시는 요청을 처리하는데 60초의 시간이 들 경우에 &lt;code&gt;graceful shutdown&lt;/code&gt;이 어떻게 되는지를 살펴본 결과인데, 하나 이상의 요청이 남아있는 와중에 &lt;code&gt;graceful shutdown&lt;/code&gt;이 중단되었다는 로그와 함께 프로세스가 종료되고 정상적으로 응답이 나가지 않았다는 걸 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;2948&quot; data-origin-height=&quot;336&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/plPP6/btszOMy6QSK/30slIgnxByq7aWQO1PiiEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/plPP6/btszOMy6QSK/30slIgnxByq7aWQO1PiiEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/plPP6/btszOMy6QSK/30slIgnxByq7aWQO1PiiEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FplPP6%2FbtszOMy6QSK%2F30slIgnxByq7aWQO1PiiEk%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;2948&quot; height=&quot;336&quot; data-filename=&quot;12.png&quot; data-origin-width=&quot;2948&quot; data-origin-height=&quot;336&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;13.png&quot; data-origin-width=&quot;432&quot; data-origin-height=&quot;266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eqoL10/btszOOXZrYb/3nS1RgNiBpqnKslbKjgnl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eqoL10/btszOOXZrYb/3nS1RgNiBpqnKslbKjgnl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eqoL10/btszOOXZrYb/3nS1RgNiBpqnKslbKjgnl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeqoL10%2FbtszOOXZrYb%2F3nS1RgNiBpqnKslbKjgnl0%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;239&quot; height=&quot;147&quot; data-filename=&quot;13.png&quot; data-origin-width=&quot;432&quot; data-origin-height=&quot;266&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;timeout 시간 조정&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;graceful shutdown&lt;/code&gt;에 대한 타임아웃은 아래의 프로퍼티로 조절할 수 있는데 기본값은 30초이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;즉 해당 프로퍼티를 따로 설정하지 않았을 때, 요청이 들어오고 30초 내에 처리가 되지 않을 경우 제대로 요청이 처리가 되지 않은채로 프로세스가 종료된다. &lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;&amp;rarr; 바로 위의 에러 로그를 보면 타임아웃에 대한 로그도 볼 수 있다&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1699181614094&quot; class=&quot;yaml&quot; data-ke-language=&quot;yaml&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  lifecycle:
    timeout-per-shutdown-phase: 2m&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;타임아웃 시간을 2분으로 늘릴 경우, 요청이 정상적으로 처리되는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;14.png&quot; data-origin-width=&quot;2596&quot; data-origin-height=&quot;336&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cR0z2U/btszKGz7LCs/KJ7i9tQfoIK8xEzsYQEfkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cR0z2U/btszKGz7LCs/KJ7i9tQfoIK8xEzsYQEfkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cR0z2U/btszKGz7LCs/KJ7i9tQfoIK8xEzsYQEfkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcR0z2U%2FbtszKGz7LCs%2FKJ7i9tQfoIK8xEzsYQEfkK%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;2596&quot; height=&quot;336&quot; data-filename=&quot;14.png&quot; data-origin-width=&quot;2596&quot; data-origin-height=&quot;336&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;15.png&quot; data-origin-width=&quot;488&quot; data-origin-height=&quot;206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dj2gL5/btszMbeXP3x/C9dFbPDrSyHaXSLqyDKpZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dj2gL5/btszMbeXP3x/C9dFbPDrSyHaXSLqyDKpZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dj2gL5/btszMbeXP3x/C9dFbPDrSyHaXSLqyDKpZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdj2gL5%2FbtszMbeXP3x%2FC9dFbPDrSyHaXSLqyDKpZ0%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;277&quot; height=&quot;117&quot; data-filename=&quot;15.png&quot; data-origin-width=&quot;488&quot; data-origin-height=&quot;206&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;물론 클라이언트 요청이 없을 경우, 요청에 대한 대기 시간은 제외하고 어플리케이션이 종료 처리된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;16.png&quot; data-origin-width=&quot;2584&quot; data-origin-height=&quot;266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/duZXeE/btszQEnoaa2/f193Gc1s8kRbWQk4cVITeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/duZXeE/btszQEnoaa2/f193Gc1s8kRbWQk4cVITeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/duZXeE/btszQEnoaa2/f193Gc1s8kRbWQk4cVITeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FduZXeE%2FbtszQEnoaa2%2Ff193Gc1s8kRbWQk4cVITeK%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;2584&quot; height=&quot;266&quot; data-filename=&quot;16.png&quot; data-origin-width=&quot;2584&quot; data-origin-height=&quot;266&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;참고) 프로세스 종료 방식&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;프로세스를&amp;nbsp;종료하는&amp;nbsp;방식에는&amp;nbsp;여러가지가&amp;nbsp;있는데,&amp;nbsp;&lt;code&gt;graceful&amp;nbsp;shutdown&lt;/code&gt;과&amp;nbsp;관련된&amp;nbsp;내용만&amp;nbsp;간단히&amp;nbsp;정리하자면&amp;nbsp;다음과&amp;nbsp;같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;SIGKILL(kill -9)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;SIGKILL&lt;/code&gt;은 프로세스를 즉시 종료시킨다. &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;그래서&amp;nbsp;&lt;code&gt;graceful&amp;nbsp;shutdown&lt;/code&gt;이&amp;nbsp;동작하지&amp;nbsp;않는다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;17.png&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;270&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUbplQ/btszKJXUflu/gsGZ34wFNX1jpKo4M5qPIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUbplQ/btszKJXUflu/gsGZ34wFNX1jpKo4M5qPIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUbplQ/btszKJXUflu/gsGZ34wFNX1jpKo4M5qPIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUbplQ%2FbtszKJXUflu%2FgsGZ34wFNX1jpKo4M5qPIk%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;344&quot; height=&quot;182&quot; data-filename=&quot;17.png&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;270&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;SIGTERM(kill -15)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;SIGKILL&lt;/code&gt;과&amp;nbsp;달리&amp;nbsp;&lt;code&gt;SIGTERM&lt;/code&gt;은&amp;nbsp;graceful하게&amp;nbsp;프로세스를&amp;nbsp;죽이는&amp;nbsp;방법이다.&amp;nbsp;&lt;code&gt;graceful&amp;nbsp;shutdown&lt;/code&gt;이&amp;nbsp;동작하게&amp;nbsp;하려면&amp;nbsp;&lt;code&gt;SIGTERM&lt;/code&gt; 방식으로 프로세스를 죽여야 한다. 위의 예시에서는 모두 &lt;code&gt;SIGTERM&lt;/code&gt;으로 프로세스를 종료했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;샘플 코드  &lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://github.com/seriouskang/spring-boot-in-action/tree/main/graceful-shutdown&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;graceful-shutdown&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;참고  &amp;zwj;♂️&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://dev.to/antonkuklin/golang-graceful-shutdown-3n6d&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Golang:&amp;nbsp;graceful&amp;nbsp;shutdown&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://www.baeldung.com/spring-boot-web-server-shutdown&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Baeldung:&amp;nbsp;Web&amp;nbsp;Server&amp;nbsp;Graceful&amp;nbsp;Shutdown&amp;nbsp;in&amp;nbsp;Spring&amp;nbsp;Boot&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>spring</category>
      <category>Graceful</category>
      <category>graceful shutdown</category>
      <category>process kill</category>
      <category>SIGKILL</category>
      <category>SIGTERM</category>
      <category>timeout-per-shutdown-phase</category>
      <category>요청 중 종료</category>
      <author>시리어스강</author>
      <guid isPermaLink="true">https://seriouskang.tistory.com/11</guid>
      <comments>https://seriouskang.tistory.com/11#entry11comment</comments>
      <pubDate>Sun, 5 Nov 2023 20:14:32 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 어플리케이션을 종료할 때 특정 작업 수행하기(feat. ApplicationListener)</title>
      <link>https://seriouskang.tistory.com/10</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;최근에 사용자가 로그만 보고 어플리케이션이 언제 종료되었는지 알고 싶다는 요구사항이 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이처럼 어플리케이션이 시작할 때, 종료될 때, 실패했을 때 등과 같이 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;어떤 이벤트가 있을 때, 특정 작업을 수행&lt;/b&gt;&lt;/span&gt;하게 하는건 언제든지 필요할 수 있으므로, 이번 기회를 통해 종료 상황에 특정 작업을 수행하는 샘플 코드를 작성해보려고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Untitled.png&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crboP7/btszLpqMvrr/5Nvcur3vk5t97R62R9ancK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crboP7/btszLpqMvrr/5Nvcur3vk5t97R62R9ancK/img.png&quot; data-alt=&quot;요구사항에 필요한 존재다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crboP7/btszLpqMvrr/5Nvcur3vk5t97R62R9ancK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrboP7%2FbtszLpqMvrr%2F5Nvcur3vk5t97R62R9ancK%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;351&quot; height=&quot;351&quot; data-filename=&quot;Untitled.png&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;474&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;요구사항에 필요한 존재다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. 샘플 프로젝트 준비&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;어떤 이벤트가 발생했을 때 특정 작업을 수행하기 위해 &lt;code&gt;ApplicationListener&lt;/code&gt; 인터페이스를 사용할 예정이고, 샘플 코드에서는 &lt;code&gt;ShutdownEventListener&lt;/code&gt;가 구현체가 될 예정이다. 그리고 어플리케이션을 기동하고 바로 종료되지 않도록 &lt;code&gt;spring-boot-starter-web&lt;/code&gt;을 의존성으로 추가했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아래에 링크로 달아둔 샘플 코드를 보면 알 수 있겠지만, 크게 복잡할 것 없는 내용이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Untitled (1).png&quot; data-origin-width=&quot;890&quot; data-origin-height=&quot;434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PzEmh/btszKcMu8Fv/QRWzXTObvcAXYKoidQJkkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PzEmh/btszKcMu8Fv/QRWzXTObvcAXYKoidQJkkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PzEmh/btszKcMu8Fv/QRWzXTObvcAXYKoidQJkkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPzEmh%2FbtszKcMu8Fv%2FQRWzXTObvcAXYKoidQJkkk%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;509&quot; height=&quot;248&quot; data-filename=&quot;Untitled (1).png&quot; data-origin-width=&quot;890&quot; data-origin-height=&quot;434&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. 리스너 추가 전&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;리스너(&lt;code&gt;ShutdownEventListener&lt;/code&gt;)가&amp;nbsp;없는&amp;nbsp;상황에서&amp;nbsp;어플리케이션을&amp;nbsp;종료하면&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;로그가&amp;nbsp;남긴하지만,&amp;nbsp;유저&amp;nbsp;친화적인&amp;nbsp;메세지는&amp;nbsp;남지&amp;nbsp;않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Untitled (2).png&quot; data-origin-width=&quot;2590&quot; data-origin-height=&quot;190&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cC25ka/btszMaNEfF0/5nvgOUjzmabz0ihZ4PsZu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cC25ka/btszMaNEfF0/5nvgOUjzmabz0ihZ4PsZu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cC25ka/btszMaNEfF0/5nvgOUjzmabz0ihZ4PsZu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcC25ka%2FbtszMaNEfF0%2F5nvgOUjzmabz0ihZ4PsZu0%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;2590&quot; height=&quot;190&quot; data-filename=&quot;Untitled (2).png&quot; data-origin-width=&quot;2590&quot; data-origin-height=&quot;190&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3. 리스너 추가 후&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;요구사항대로 유저가 직관적으로 어플리케이션이 종료되었음을 알 수 있도록 리스너를 생성하여 로그 메세지를 출력한다. 단, 어플리케이션이 종료되는 시점에 메세지를 출력해야 하므로 어플리케이션 이벤트는 &lt;code&gt;ContextClosedEvent&lt;/code&gt;로&amp;nbsp;설정한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;ShutdownEventListener&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1699110495388&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
@Component
public class ShutdownEventListener implements ApplicationListener&amp;lt;ContextClosedEvent&amp;gt; {
    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        log.info(&quot;application shutdown!&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;결과&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Untitled (3).png&quot; data-origin-width=&quot;2590&quot; data-origin-height=&quot;226&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qUeG8/btszMbFNcVy/ranzqNWqM7vkFZsAVn6bu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qUeG8/btszMbFNcVy/ranzqNWqM7vkFZsAVn6bu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qUeG8/btszMbFNcVy/ranzqNWqM7vkFZsAVn6bu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqUeG8%2FbtszMbFNcVy%2FranzqNWqM7vkFZsAVn6bu1%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;2590&quot; height=&quot;226&quot; data-filename=&quot;Untitled (3).png&quot; data-origin-width=&quot;2590&quot; data-origin-height=&quot;226&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;리스너를 추가하여 어플리케이션이 종료되는 시점에 별도의 로그 메세지를 남길 수 있게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;요구사항은 단순히 로깅을 남기는 것에 그쳤지만, &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;리스너 메소드에 다른 로직을 넣어서 처리하거나 대상 이벤트 자체를 변경한다면 다양한 상황에 맞춰 특정 작업을 수행할 수 있을 것이다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;샘플 코드  &lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://github.com/seriouskang/spring-boot-in-action/tree/main/context-closed-event&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;context-closed-event&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;참고 자료  &amp;zwj;♂️&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/event/ContextClosedEvent.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;spring&amp;nbsp;docs:&amp;nbsp;ContextClosedEvent&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>spring</category>
      <category>ApplicationListener</category>
      <category>ContextClosedEvent</category>
      <category>event</category>
      <category>SHUTDOWN</category>
      <category>어플리케이션 종료</category>
      <category>이벤트</category>
      <category>종료</category>
      <category>특정 작업</category>
      <author>시리어스강</author>
      <guid isPermaLink="true">https://seriouskang.tistory.com/10</guid>
      <comments>https://seriouskang.tistory.com/10#entry10comment</comments>
      <pubDate>Sun, 5 Nov 2023 00:19:21 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] @SpringBootApplication가 없는 상황에서 @SpringBootTest 수행하기</title>
      <link>https://seriouskang.tistory.com/9</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;회사 동료 분이 스프링 테스트를 하며 오류가 난다고 도움을 요청하셨는데, 살펴보니 크게 두 가지 이슈가 있었고 주요 문제는 &lt;code&gt;@SpringBootApplication&lt;/code&gt;&amp;nbsp;클래스를 포함하지 않는 프로젝트라 &lt;code&gt;@SpringBootTest&lt;/code&gt;가 수행이 되지 상황이었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이와 관련해서 자료를 찾다보니 마음에 드는 답변은 스프링 테스트 전반에 걸친 내용을 작성한 글 중 일부로 있었고, 간단한 해결 방법들은 지금과 같은 상황에서 좋은 해결책은 아니었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래서 샘플 코드와 함께 내 나름대로의 해결 방식을 정리를 해두려고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qyOys/btsp3mrdVhG/e8sqQPxCukoLSinx3OHI31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qyOys/btsp3mrdVhG/e8sqQPxCukoLSinx3OHI31/img.png&quot; data-alt=&quot;올해 처음으로 회사에서 테스트 코드로 고민하는 분을 봐 반가웠다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qyOys/btsp3mrdVhG/e8sqQPxCukoLSinx3OHI31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqyOys%2Fbtsp3mrdVhG%2Fe8sqQPxCukoLSinx3OHI31%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;393&quot; height=&quot;382&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;올해 처음으로 회사에서 테스트 코드로 고민하는 분을 봐 반가웠다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. 프로젝트 준비&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;에러&amp;nbsp;재현을&amp;nbsp;위해&amp;nbsp;구성한&amp;nbsp;프로젝트는&amp;nbsp;다음과&amp;nbsp;같다.&amp;nbsp;특이&amp;nbsp;사항이라면,&amp;nbsp;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;어플리케이션을&amp;nbsp;기동하기&amp;nbsp;위한&amp;nbsp;엔트리&amp;nbsp;포인트가&amp;nbsp;없다는&amp;nbsp;것&lt;/b&gt;&lt;/span&gt;이고&amp;nbsp;다음으로&amp;nbsp;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;&lt;code&gt;SampleService&lt;/code&gt;가&amp;nbsp;의존하고&amp;nbsp;있는&amp;nbsp;&lt;code&gt;SampleRepository&lt;/code&gt;&amp;nbsp;구현체가&amp;nbsp;해당&amp;nbsp;프로젝트에는&amp;nbsp;없다&lt;/b&gt;&lt;/span&gt;는&amp;nbsp;점이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dyMXeQ/btsp34qsvy4/yVLrmwDYKs2iBTE4oOJsg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dyMXeQ/btsp34qsvy4/yVLrmwDYKs2iBTE4oOJsg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dyMXeQ/btsp34qsvy4/yVLrmwDYKs2iBTE4oOJsg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdyMXeQ%2Fbtsp34qsvy4%2FyVLrmwDYKs2iBTE4oOJsg0%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;444&quot; height=&quot;308&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;어플리케이션 아키텍처는 아래 그림과 같이 &lt;code&gt;DIP&lt;/code&gt;를 적용해, 어플리케이션 레이어의 서비스가 레포지토리 빈을(&lt;code&gt;저수준 모듈&lt;/code&gt;) 직접 의존하는 것이 아니라 도메인 레이어의 인터페이스를(&lt;code&gt;고수준 모듈&lt;/code&gt;) 의존하도록 구성하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;1102&quot; data-origin-height=&quot;882&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D3ouV/btsp9qeMw2L/pgY3YQEkKbeiIZLNrIn7XK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D3ouV/btsp9qeMw2L/pgY3YQEkKbeiIZLNrIn7XK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D3ouV/btsp9qeMw2L/pgY3YQEkKbeiIZLNrIn7XK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD3ouV%2Fbtsp9qeMw2L%2FpgY3YQEkKbeiIZLNrIn7XK%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;519&quot; height=&quot;415&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;1102&quot; data-origin-height=&quot;882&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. 테스트 에러 재현&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;테스트&amp;nbsp;코드를&amp;nbsp;아래와&amp;nbsp;같이&amp;nbsp;작성했을&amp;nbsp;때&amp;nbsp;문제가&amp;nbsp;되는&amp;nbsp;부분은&amp;nbsp;먼저&amp;nbsp;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;서비스에서&amp;nbsp;의존하고&amp;nbsp;있는&amp;nbsp;리포지토리&amp;nbsp;객체가&amp;nbsp;없다는&amp;nbsp;점&lt;/b&gt;&lt;/span&gt;이고,&amp;nbsp;다음으로는&amp;nbsp;&lt;code&gt;@SpringBootApplication&lt;/code&gt;&amp;nbsp;어노테이션을&amp;nbsp;사용하는&amp;nbsp;클래스가&amp;nbsp;없으므로&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;code&gt;@SpringBootTest&lt;/code&gt;가&amp;nbsp;사용하는&amp;nbsp;&lt;code&gt;@SpringBootConfiguration&lt;/code&gt;을&amp;nbsp;찾을&amp;nbsp;수&amp;nbsp;없다는&amp;nbsp;점&lt;/span&gt;&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1691224261145&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@SpringBootTest
class BootApplicationTests {
    @Autowired
    SampleService sampleService;

    @Test
    void di_test() {
        assertThat(sampleService.findContentsById(1L))
                .isEqualTo(&quot;hello, 1&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;에러 메세지&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;2820&quot; data-origin-height=&quot;594&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9NfBT/btsp19yXqdj/kNBf9t2EeykIKsx4wr7kq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9NfBT/btsp19yXqdj/kNBf9t2EeykIKsx4wr7kq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9NfBT/btsp19yXqdj/kNBf9t2EeykIKsx4wr7kq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9NfBT%2Fbtsp19yXqdj%2FkNBf9t2EeykIKsx4wr7kq1%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;2820&quot; height=&quot;594&quot; data-filename=&quot;4.png&quot; data-origin-width=&quot;2820&quot; data-origin-height=&quot;594&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1691224294827&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;border-bottom: 1px solid black; padding: 0.1em; font-weight: bold;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3. 해결&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;@SpringBootConfiguration&lt;/code&gt;을&amp;nbsp;찾을&amp;nbsp;수&amp;nbsp;없어서&amp;nbsp;발생하는&amp;nbsp;문제는&amp;nbsp;&lt;code&gt;@SpringBootApplication&lt;/code&gt; 어노테이션을 사용하는 클래스가 있을 경우 발생하지 않게 할 수 있고, 실제로 몇몇 블로그나 포스팅에서는&amp;nbsp;&lt;code&gt;@SpringBootApplication&lt;/code&gt;을&amp;nbsp;생성해서&amp;nbsp;사용하라는&amp;nbsp;답변도&amp;nbsp;있었다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;참고: @SpringBootApplication&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1691224340302&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration  
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만, &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;다른 어플리케이션의 의존성으로 사용하기 위해 만든 프로젝트에서 어플리케이션의 엔트리포인트가 되는 어노테이션을 사용할 필요가 없으므로&lt;/b&gt;&lt;/span&gt; 다른 방식으로 해결하려고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;테스트 코드&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;에러 메세지에 친절히 나와있는 것처럼 &lt;code&gt;@SpringBootTest&lt;/code&gt; 어노테이션 내에 &lt;code&gt;classes&lt;/code&gt; 속성을 활용해, &lt;code&gt;@Configuration&lt;/code&gt; 클래스를 지정한다. 참고로, &lt;code&gt;classes&lt;/code&gt; 속성은 지정한 클래스를 빈으로 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691224426247&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@SpringBootTest(classes = SampleRepositoryConfiguration.class)
class BootApplicationTests {
    @Autowired
    SampleService sampleService;

    @Test
    void di_test() {
        assertThat(sampleService.findContentsById(1L))
                .isEqualTo(&quot;hello, 1&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;configuration&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;@SpringBootTest&lt;/code&gt;의&amp;nbsp;&lt;code&gt;classes&lt;/code&gt; 속성으로 지정한 클래스에서는 서비스에서 의존하고 있는 리포지토리의 구현체를 만들고, &lt;code&gt;@ComponentScan&lt;/code&gt;&amp;nbsp;어노테이션을&amp;nbsp;활용해&amp;nbsp;테스트에서&amp;nbsp;필요한&amp;nbsp;빈들을&amp;nbsp;생성하도록&amp;nbsp;한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691224464485&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@ComponentScan(basePackages = &quot;com.example&quot;)
public class SampleRepositoryConfiguration {
    @Bean
    public SampleRepository sampleRepository() {
        return id -&amp;gt; &quot;hello, &quot; + id;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;테스트 결과&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;테스트를 위한 리포지토리 구현체를 만들어 서비스 빈을 정상적으로 생성하여, 테스트가 통과했다는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;1184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wptKL/btsp7AI8Vlt/07ZVWNGS3mZ9MBuNH4f1Pk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wptKL/btsp7AI8Vlt/07ZVWNGS3mZ9MBuNH4f1Pk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wptKL/btsp7AI8Vlt/07ZVWNGS3mZ9MBuNH4f1Pk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwptKL%2Fbtsp7AI8Vlt%2F07ZVWNGS3mZ9MBuNH4f1Pk%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;595&quot; height=&quot;522&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;1350&quot; data-origin-height=&quot;1184&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;샘플 코드  &lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://github.com/seriouskang/spring-boot-in-action/tree/main/spring-boot-test-without-spring-boot-application/src&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;spring-boot-test-without-spring-boot-application&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>spring</category>
      <category>@SpringBootApplication</category>
      <category>@SpringBootConfiguration</category>
      <category>@SpringBootTest</category>
      <category>classes</category>
      <author>시리어스강</author>
      <guid isPermaLink="true">https://seriouskang.tistory.com/9</guid>
      <comments>https://seriouskang.tistory.com/9#entry9comment</comments>
      <pubDate>Sat, 5 Aug 2023 17:38:45 +0900</pubDate>
    </item>
  </channel>
</rss>