<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>INTP 개발자</title>
    <link>https://yeo-computerclass.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 14 Apr 2026 21:37:18 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>민팁(MINTIP)</managingEditor>
    <item>
      <title>[Spring Batch] 왜 Spring Batch를 사용하나?</title>
      <link>https://yeo-computerclass.tistory.com/596</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Spring Batch란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스를 운영하다 보면, 한 번에 대량의 데이터를 안정적으로 처리해야 하는 순간이 자주 찾아옵니다. 예를 들어 매일 새벽에 수백만 건의 주문 데이터를 집계해 정산 리포트를 만들거나, 외부에서 제공한 대량 파일을 검증 후 DB에 적재하는 경우죠. 이런 작업들은 단순한 웹 요청-응답 패턴으로는 처리 하기 힘듭니다. 처리 중간에 실패할 수도 있고, 수십만 건을 한 번에 트랜잭션으로 다루기엔 부담이 크며, 중간에 멈췄을 때 어디서부터 다시 시작할지도 관리해야 하기 때문이죠.&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;Spring Batch의 등장&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 요구를 해결하기 위해 만들어진 프레임워크가 바로 &lt;b&gt;&lt;i&gt;Spring Batch&lt;/i&gt;&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Batch는 &lt;b&gt;대규모 데이터를 읽고 &amp;rarr; 가공하고 &amp;rarr; 저장&lt;/b&gt;하는 과정을 표준화한 프레임워크예요. 단순히 데이터를 처리하는 것뿐만 아니라, &lt;b&gt;실패 시 재시작&lt;/b&gt;, &lt;b&gt;처리 이력 관리&lt;/b&gt;, &lt;b&gt;병렬 처리&lt;/b&gt;, &lt;b&gt;최적화 기법&lt;/b&gt;까지 갖추고 있어 엔터프라이즈 환경에서 매일 수십억 건의 데이터를 안정적으로 처리할 수 있어요.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;대랑 데이터 처리:&lt;/b&gt; DB, 파일, 메시지 큐 등에서 대규모 데이터를 읽어 가공하고 저장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실패 후 재시작:&lt;/b&gt; 중단된 지점부터 다시 이어서 실행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;처리 이력 관리:&lt;/b&gt; 언제, 어떤 데이터가 처리됐는지 추적&lt;/li&gt;
&lt;li&gt;&lt;b&gt;에러/스킵 처리:&lt;/b&gt; 잘못된 데이터만 건너뛰고 나머지는 계속 진행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능 최적화와 병렬 처리:&lt;/b&gt; 파티녀싱, 멀티스레드로 초대량 데이터도 빠르게 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 기능을 프레임워크 차원에서 제공하기 때문에, 매일 수억~수십억 건의 데이터를 다루는 시스템에서도 신뢰성 있게 운영할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;⚠️&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;스케줄러와는 다릅니다&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스케줄러(Spring&amp;nbsp;Scheduler,&amp;nbsp;Quartz,&amp;nbsp;Cron&amp;nbsp;등)는&amp;nbsp;&quot;언제&amp;nbsp;실행할지&quot;를&amp;nbsp;결정합니다.&amp;nbsp;&lt;br /&gt;예: 매일 자정에 Job 실행&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Spring&amp;nbsp;Batch는&amp;nbsp;&quot;어떻게&amp;nbsp;대량&amp;nbsp;데이터를&amp;nbsp;안정적으로&amp;nbsp;처리할지&quot;를&amp;nbsp;담당합니다.&amp;nbsp;&lt;br /&gt;예:&amp;nbsp;CSV&amp;nbsp;100만&amp;nbsp;건을&amp;nbsp;1,000건&amp;nbsp;단위로&amp;nbsp;나눠서&amp;nbsp;읽고,&amp;nbsp;가공한&amp;nbsp;뒤,&amp;nbsp;DB에&amp;nbsp;저장&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉,&amp;nbsp;둘은&amp;nbsp;대체&amp;nbsp;관계가&amp;nbsp;아니라&amp;nbsp;보완&amp;nbsp;관계입니다.&amp;nbsp;운영&amp;nbsp;환경에서는&amp;nbsp;보통&amp;nbsp;스케줄러가&amp;nbsp;Job을&amp;nbsp;호출하고,&amp;nbsp;Spring&amp;nbsp;Batch가&amp;nbsp;데이터를&amp;nbsp;안전하게&amp;nbsp;처리하는&amp;nbsp;구조로&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 배치 프로그램은 다음과 같은 반복 패턴을 따릅니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;데이터 읽기: DB, 파일, 메시지 큐 등에서 대량의 데이터를 읽고,&lt;/li&gt;
&lt;li&gt;데이터 가공: 데이터를 비즈니스 규칙에 맞게 가공한 뒤,&lt;/li&gt;
&lt;li&gt;데이터 저장: 다시 DB나 파일에 저장.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Batch는 이 단순한 패턴 위에, &lt;i&gt;로깅&lt;/i&gt;, &lt;i&gt;트랜잭션 관리&lt;/i&gt;, &lt;i&gt;재시작/스킵 처리&lt;/i&gt;, &lt;i&gt;병렬 처리&lt;/i&gt; 같은 기능을 프레임워크 차원에서 제공해, 개발자가 직접 인프라를 구현하지 않아도 되게 해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;사용 사례&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 기본 패턴은 다양한 비즈니스 환경에 적용됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;금융권: 월말 결산, 보험료 계산, 청구서 발송&lt;/li&gt;
&lt;li&gt;이커머스: 대량 주문 데이터 적재 및 재고 업데이트&lt;/li&gt;
&lt;li&gt;공공기관: 대규모 민원 테이터 처리 및 보고소 생성&lt;/li&gt;
&lt;li&gt;로그 수집 후 통계 집계 등&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉,&amp;nbsp;&lt;b&gt;대량 데이터 + 반복적인 처리 + 높은 신뢰성&lt;/b&gt;이 필요한 곳이라면 어디든 Spring Batch의 적용 대상이 됩니다.&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Batch는 단순한 라이브러리가 아니라, 대규모 데이터 처리를 안정적이고 표준화된 방식으로 운영할 수 있게 해주는 프레임워크입니다. 스케줄러가 언제 실행할지를 관리한다면, Spring Batch는 어떻게 안정적으로 처리할지를 책임집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  다음 글에서는 Spring Batch의 &lt;b&gt;Architecture&lt;/b&gt;를 살펴보며, 개발자가 어떤 부분을 직접 작성하고, 프레임워크가 어떤 부분을 대신 처리하는지 구체적으로 알아보겠습니다.&lt;/p&gt;</description>
      <category>Spring/Spring Batch</category>
      <category>batch</category>
      <author>민팁(MINTIP)</author>
      <guid isPermaLink="true">https://yeo-computerclass.tistory.com/596</guid>
      <comments>https://yeo-computerclass.tistory.com/596#entry596comment</comments>
      <pubDate>Sun, 31 Aug 2025 22:52:24 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] Dockerfile이 뭔데? 도커 이미지를 만들기 위한 설계도</title>
      <link>https://yeo-computerclass.tistory.com/595</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이전 포스팅들에서는 Docker Hub에 올라온 이미지를 받아서, 실행해 보는 방식으로 Docker를 다뤘어요. Ubuntu, Nginx, MySQL 등 남이 만들어둔 환경 위에서 내 코드를 올려보는 실습을 했죠.&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&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;Dockerfile&lt;/i&gt;입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;왜 Dockerfile이 필요한가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dockerfile은 도커 이미지를 만드는 설계도 파일이에요. 어떤 OS에서, 어떤 패키지를 설치하고, 어떤 파일을 복사하고, 어떤 명령어로 실행할지 등을 단계별로 이 한 파일에 모두 정의할 수 있죠. Docker는 이 Dockerfile을 읽고 한 단계씩 따라가면서 이미지를 빌드해 줘요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 개발&amp;middot;배포 환경에서는 거의 대부분 Dockerfile을 직접 작성하게 돼요. CI/CD 파이프라인에서도 이 Dockerfile을 기준으로 빌드&amp;middot;배포가 자동화되죠.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;Dockerfile 도입 목적과 장점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;환경 일관성 보장: 개발 환경, 운영 환경 모두 동일하게 구성 가능&lt;/li&gt;
&lt;li&gt;자동화: CI/CD 파이프라인과 연동하여 배포 자동화가 가능&lt;/li&gt;
&lt;li&gt;최적화 가능: Layer 캐싱 및 빌드 최적화로 속도 향상&lt;/li&gt;
&lt;li&gt;버전 관리: Git으로 관리 가능하여 변경 추적 및 롤백이 수월&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;Dockerfile 기본 구조&lt;/h2&gt;
&lt;pre id=&quot;code_1754828283315&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD [&quot;node&quot;, &quot;index.js&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;Dockerfile 명령어 정리&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;1. FROM&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 이미지를 베이스로 사용할지 정해요.&lt;/li&gt;
&lt;li&gt;대부분&amp;nbsp;&lt;i&gt;ubuntu&lt;/i&gt;,&amp;nbsp;&lt;i&gt;node&lt;/i&gt;,&amp;nbsp;&lt;i&gt;python&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은 공식 이미지를 가져와요&lt;/li&gt;
&lt;li&gt;반드시 가장 첫 줄 작성되어야 해요.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1754828283315&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;FROM ubuntu:22.04

FROM scratch&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;i&gt;scratch&lt;/i&gt;는 아무것도 없는 빈 이미지로, 최적화된 최소 이미지 제작에 유용해요. (Golang, Rust 등 정적 바이너리에서 사용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;2. LABEL&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미지에 메타데이터(정보) 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1754828283316&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;LABEL maintainer=&quot;MINTP&quot; \
      description=&quot;MINTP&quot; \
      version=&quot;1.0&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;3. WORKDIR&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;명령어가 실행될 기본 디렉터리를 지정해요.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1754828283316&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;WORKDIR /app&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; 지정한 경로가 없으면 자동으로 만들어줘요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;4. COPY &amp;amp; ADD&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 파일을 이미지 안으로 복사해요.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1754828283316&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;COPY . .&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;&lt;i&gt;ADD&lt;/i&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;COPY&lt;/i&gt;와 거의 비슷하지만, URL 다운로드나 압축 해제 기능이 있어요.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1754828283316&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;ADD https://example.com/app.tar.gz /app/&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;⚠️ ADD 지양하기&lt;/b&gt;&lt;br /&gt;ADD는 압축 해제나 원격 URL 다운로드 같은 기능도 포함돼 있어서, 상황에 따라 동작이 예측하기 어렵거나 의도치 않게 보안 취약점을 만들 수 있어요. 그래서 특별한 목적이 있는 경우가 아니라면 COPY를 사용하는 게 더 안전해요. 특별한 경우 아니면 COPY를 써요.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;&lt;b&gt; ADD 없이 URL 다운로드 &amp;amp; 압축 해제하기&lt;/b&gt;&lt;br /&gt;1. URL 다운로드는 curl 또는 wget 사용&lt;br /&gt;
&lt;pre id=&quot;code_1754828283316&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;RUN apt-get update &amp;amp;&amp;amp; apt-get install -y curl \
  &amp;amp;&amp;amp; curl -L https://intpdev.com/app.tar.gz -o /tmp/app.tar.gz​&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;2. 압축 해제는 tar 사용&lt;/p&gt;
&lt;pre id=&quot;code_1754828283316&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;RUN tar -xzf /tmp/app.tar.gz -C /app &amp;amp;&amp;amp; rm /tmp/app.tar.gz​&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;  ADD 없이도 같은 기능을 명확하게 제어하면서 구현할 수 있어요.&lt;br /&gt;⚠️ curl로 다운로드하는 결과물이 매번 다르거나 변경될 가능성이 있는 경우, Docker의 빌드 캐시가 무효화될 수 있어요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;5. RUN&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미지를 만들 때 실행되는 셸 명령어예요.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1754828283317&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;RUN apt update
RUN apt install -y git
RUN apt clean -y
RUN apt autoremove -y
RUN rm -rfv /tmp/* /var/lib/apt/lists/* /var/tmp/*

# 권장 사항
RUN apt update &amp;amp;&amp;amp; \
	apt install -y git \
            curl &amp;amp;&amp;amp; \
	apt clean -y &amp;amp;&amp;amp; \
	apt autoremove -y &amp;amp;&amp;amp; \
	rm -rfv /tmp/* /var/lib/apt/lists/* /var/tmp/*&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;여러&amp;nbsp;RUN&amp;nbsp;명령어는&amp;nbsp;&amp;amp;&amp;amp;로&amp;nbsp;묶어서&amp;nbsp;한&amp;nbsp;줄에&amp;nbsp;쓰면&amp;nbsp;이미지&amp;nbsp;레이어&amp;nbsp;수를&amp;nbsp;줄일&amp;nbsp;수&amp;nbsp;있어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;6. CMD&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너가 실행될 때 기본으로 실행되는 명령어예요.&lt;/li&gt;
&lt;li&gt;Dockerfile에서 한 번만 쓸 수 있어요. 여러 개의 CMD를 작성해도 마지막 명령만 처리됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1754828283317&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;CMD [&quot;node&quot;, &quot;index.js&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;i&gt;docker run&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;명령에서 실행 명령을 따로 넘기면 Dockerfile에 정의된 CMD는 무시돼요.&lt;/p&gt;
&lt;pre id=&quot;code_1754828283317&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;FROM ubuntu
CMD [&quot;echo&quot;, &quot;hello from CMD&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1754828283317&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;docker run my-image                        # echo hello from CMD
docker run my-image &quot;hello again&quot;   # echo hello again&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  CMD는 완전히 덮어쓰기 됨&lt;/p&gt;
&lt;pre id=&quot;code_1754828283317&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;ENTRYPOINT [&quot;/entrypoint.sh&quot;]
CMD [&quot;--mode=dev&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &amp;nbsp;&lt;i&gt;docker run my-image --mode=prod&lt;/i&gt;도 유연하게 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;7. ENTRYPOINT&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CMD랑 비슷하지만, &quot;고정된 실행 파일&quot;을 지정할 때 사용해요.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1754828283318&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;FROM ubuntu
ENTRYPOINT [&quot;echo&quot;, &quot;hello from ENTRYPOINT&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1754828283318&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;docker run my-image                  # echo hello from ENTRYPOINT
docker run my-image &quot;again&quot;         # echo hello from ENTRYPOINT again&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  ENTRYPOINT는 고정되고, 인자만 추가됨&lt;/p&gt;
&lt;pre id=&quot;code_1754828283318&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;ENTRYPOINT [&quot;/entrypoint.sh&quot;]
CMD [&quot;--dev&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 실제 실행 명령:&amp;nbsp;&lt;i&gt;/entrypoint.sh --dev&lt;/i&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;  ENTRYPOINT는 &quot;컨테이너가 항상 실행해야 할 주 명령어&quot;를 고정하는데 쓰고, CMD는 그 명령어에 전달할 기본 인자를 지정하는 데 사용한 형식입니다. CMD는 쉽게 덮어쓸 수 있기 때문에, 고정된 실행 파일이 있을 땐 ENTRYPOINT, 유동적인 인자가 있을 때 CMD를 함께 쓰는 방식이 유용해요 (&lt;i&gt;고정 실행 파일&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;+&amp;nbsp;&lt;i&gt;유동 파라미터&lt;/i&gt;)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;8. ENV&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;환경 변수를 설정해요.&lt;/li&gt;
&lt;li&gt;형식은 일반적으로&amp;nbsp;&lt;i&gt;ENV 키=값&lt;/i&gt;이지만,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;ENV 키 값&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;형태도 사용할 수 있어요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ENV는 두 가지 목적에서 사용돼요:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;애플리케이션 실행 시 필요한 환경 변수 미리 정의&lt;/li&gt;
&lt;li&gt;Dockerfile 내에서 반복되는 값을 재사용 (예:&amp;nbsp;&lt;i&gt;ENV APP_HOME /app&lt;/i&gt;) 이후 여러 RUN, WORKDIR, COPY, CMD 명령에서&amp;nbsp;&lt;i&gt;$APP_HOME&lt;/i&gt;을 사용해 반복을 피할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1754828283319&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;ENV MYSQL_ROOT_PASSWORD=mypassword
ENV MYSQL_DATABASE mydb&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1754828283319&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;ENV APP_HOME=/app
WORKDIR $APP_HOME
COPY . $APP_HOME
RUN mkdir -p $APP_HOME/logs &amp;amp;&amp;amp; chmod 755 $APP_HOME/logs&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;9. EXPOSE&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너가 외부에 열 포트를 알려줘요 (자동으로 열리지 않아요).&lt;/li&gt;
&lt;li&gt;이미지 내에 애플리케이션이 사용하는 포트를 사전에 확인하고 호스트와 연결되도록 구성하는 경우 설정하고,&amp;nbsp;&lt;i&gt;docker run&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용 시 포트를 연결해 주어야(-p) 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1754828283320&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;EXPOSE 3000&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;10. ARG&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;i&gt;빌드(docker build&lt;/i&gt;)할 때 넘겨주는 변수예요. 전달하기 위해&amp;nbsp;&lt;i&gt;--build-arg=인자&lt;/i&gt;를 정의하여 사용해야 해요.&lt;/li&gt;
&lt;li&gt;ENV랑 다르게 컨테이너 안에는 남지 않아요.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1754828283320&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;ARG VERSION
ENV VERSION=$VERSION&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드할 때:&lt;/p&gt;
&lt;pre id=&quot;code_1754828283320&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;docker build --build-arg VERSION=1.0 .&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;11. USER&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너에서 명령어를 실행할 사용자를 지정해요.&lt;/li&gt;
&lt;li&gt;컨테이너 기본 사용자는&amp;nbsp;&lt;i&gt;root&lt;/i&gt;예요. 보안을 위해 사용자 계정을 지정하는 게 좋아요.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1754828283320&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;RUN adduser -D appuser
USER appuser&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;12. VOLUME&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너와 호스트가 공유하는 볼륨 디렉터리를 설정합니다. VOLUME으로 지정된 경로는&amp;nbsp;&lt;i&gt;/var/lib/docker&lt;/i&gt;와 자동으로 연결됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1754828283320&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;VOLUME [&quot;/data&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너 내부의 /data와 연결됩니다.&lt;/p&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;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;Dockerfile 최적화하기&lt;/h2&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;✅ 캐시를 잘 활용하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker는 Dockerfile의 각 명령어를 실행할 때마다 중간 결과를&amp;nbsp;&lt;b&gt;레이어(layer)&lt;/b&gt;로 저장하고, 이후 빌드에서 같은 명령이 있다면 이전 레이어를 재사용해요. 이걸 '빌드 캐시'라고 해요.&lt;/p&gt;
&lt;pre id=&quot;code_1754828283320&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# 덜 바뀌는 패키지 설치 &amp;rarr; 캐시 재사용
COPY package*.json ./     # 의존성 파일만 먼저 복사
RUN npm install           # 의존성 설치

# 자주 바뀌는 소스 코드는 마지막에 COPY
COPY . .                  # 전체 소스 복사&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소스코드는 자주 바뀌지만&amp;nbsp;&lt;i&gt;package.json&lt;/i&gt;은 잘 안 바뀌니까, 먼저 COPY 하면&amp;nbsp;&lt;i&gt;npm install&lt;/i&gt;은 캐시로 재사용 가능해요.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;✅&lt;span&gt;&amp;nbsp; RUN 명령 최소화 (Layer 줄이기)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RUN 명령마다 새로운 레이어가 생겨 이미지 크기가 증가합니다. &amp;amp;&amp;amp;를 활용해 여러 명령을 하나의 RUN으로 묶어야 해요.&lt;/p&gt;
&lt;pre id=&quot;code_1754828283321&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# 나쁜 예
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get clean

# 좋은 예
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y curl \
  &amp;amp;&amp;amp; apt-get clean&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;여러 RUN을 하나로 묶으면 불필요한 레이어가 줄어들고 불필요한 이미지 용량도 줄어들어요.&lt;/li&gt;
&lt;li&gt;도커 이미지는 레이어 단위로 캐시 되기 때문에,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;apt-get update&lt;/i&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;install&lt;/i&gt;의 중간 결과가 남고&amp;nbsp;&lt;i&gt;clean&lt;/i&gt;은 나중에 실행되기 때문에 이전 레이어는 그대로 유지돼요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  불필요한 레이어 병합&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 COPY, ENV, RUN 등이 너무 쪼개져있으며 레이어가 많아져요. 비슷한 작업을 묶어서 처리하는 것이 좋습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1754828283321&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# 나쁜 예
ENV A=1
ENV B=2

# 좋은 예
ENV A=1 B=2&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;✅ 불필요한 바이너리와 캐시 제거&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임시 파일이나 패키지 캐시가 남으면 이미지가 부풀려지기 때문에, 빌드 마지막에 임시 파일과 패키지 캐시를 삭제하는 것은 이미지 경령화에 효과적입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1754828283321&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;RUN apt-get update \
 &amp;amp;&amp;amp; apt-get install -y --no-install-recommends curl unzip openjdk-17-jdk \
 &amp;amp;&amp;amp; apt-get clean autoclean \
 &amp;amp;&amp;amp; apt-get autoremove -y \
 &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*&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;&lt;i&gt;apt-get autoremove&lt;/i&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;clean&lt;/i&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;rm -rf&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;명령으로 캐시와 임시 파일을 제거하면 경량화에 도움이 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;--no-install-recommends&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;옵션은 의존성으로 추천된 추가 패키지들을 설치하지 않도록 해서 이미지 크기를 줄여줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;✅&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;.dockerignore&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Git, node_modules, 테스트 파일까지 이미지에 포함될 수 있어요. 불필요한 파일은 빌드 시 제외해야 해요.&lt;/p&gt;
&lt;pre id=&quot;code_1754828283321&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;.git
node_modules
tests/
Dockerfile~
README.md&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;✅ Multi-stage Build&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드 도구/의존성으로 인해 이미지가 크게 증가할 수 있어요. 때문에 빌드를 먼저 하고, 결과물에 복사하는 방식을 사용할 수 있어요.&lt;/p&gt;
&lt;pre id=&quot;code_1754828283322&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# Step 1: 빌드 전용
FROM node:18 AS builder
WORKDIR /app
COPY . .
RUN npm install &amp;amp;&amp;amp; npm run build

# Step 2: 실행용 (빌드 결과물만)
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
CMD [&quot;node&quot;, &quot;dist/index.js&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;✅ scratch, Alpine Linux 활용한 이미지 경량화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;scratch&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이미지는 아무것도 포함되지 않은 완전&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;빈 베이스 이미지&lt;/b&gt;예요. 정적으로 컴파일된 Go, Rust앱에 적합해요.&lt;/p&gt;
&lt;pre id=&quot;code_1754828283322&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;FROM scratch
COPY mybinary /mybinary
ENTRYPOINT [&quot;/mybinary&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;i&gt;Alpine Linux&lt;/i&gt;는 매우 작고 경량화된 리눅스 배포판이에요. glibc 대신 musl 사용하므로, 일부 라이브러리 호환 이슈 주의가 필요해요.&lt;/p&gt;
&lt;pre id=&quot;code_1754828283322&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;FROM alpine&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Docker</category>
      <category>Docker</category>
      <author>민팁(MINTIP)</author>
      <guid isPermaLink="true">https://yeo-computerclass.tistory.com/595</guid>
      <comments>https://yeo-computerclass.tistory.com/595#entry595comment</comments>
      <pubDate>Sun, 10 Aug 2025 21:20:10 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] 도커 볼륨이 뭔데? 컨테이너 데이터 영속성 있게 안전하게 저장하는 방법</title>
      <link>https://yeo-computerclass.tistory.com/594</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너 기술을 익히다 보면 누구나 한 번쯤은 겪는 고민이 있어요&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;&quot;데이터는 컨테이너에 잘 저장됐는데, 컨테이너를 삭제하니 사라졌어요. 왜죠?&quot;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이런 문제는 Docker의 특성상 너무나 자연스러운 현상이에요. 그리고 이 문제를 깔끔하게 해결해 주는 기능이 바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;Volume&lt;/i&gt;입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;왜 Volume이 필요할까?&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker의 컨테이너는 기본적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;휘발성&lt;/i&gt;이에요. 컨테이너 내부에 데이터를 저장해도, 컨테이너가 삭제되면 데이터도 함께 사라져요. 하지만 이런 데이터는 쉽게 날아가면 안 되겠죠?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스의 사용자 데이터&lt;/li&gt;
&lt;li&gt;로그 파일&lt;/li&gt;
&lt;li&gt;사용자가 업로드한 이미지 등 정적 리소스&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이런 데이터는 컨테이너의 라이프사이클과는 독립적으로 영구 보존 되어야 해요. 이럴 때 필요한 것이 바로 Volume이에요.&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;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;도커 볼륨의 세 가지 방식&lt;/h2&gt;
&lt;table style=&quot;color: #000000; text-align: start; border-collapse: collapse; width: 100%; height: 80px;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot; data-ke-align=&quot;alignLeft&quot; data-pm-slice=&quot;3 3 []&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 14.7674%; height: 20px;&quot;&gt;&lt;b&gt;&lt;span&gt;방식&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 31.6279%; height: 20px;&quot;&gt;&lt;b&gt;&lt;span&gt;설명&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.7675%; height: 20px;&quot;&gt;&lt;b&gt;&lt;span&gt;특징&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 28.7209%; height: 20px;&quot;&gt;&lt;b&gt;&lt;span&gt;예시&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 14.7674%; height: 20px;&quot;&gt;&lt;i&gt;&lt;span&gt;&lt;b&gt;Volume&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td style=&quot;width: 31.6279%; height: 20px;&quot;&gt;&lt;span&gt;Docker가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;내부&lt;/span&gt;에서 직접 관리&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.7675%; height: 20px;&quot;&gt;&lt;span&gt;영속성 뛰어남, 백업 편리&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 28.7209%; height: 20px;&quot;&gt;&lt;span&gt;운영 환경의 DB, 앱 데이터&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 14.7674%; height: 20px;&quot;&gt;&lt;i&gt;&lt;span&gt;&lt;b&gt;Bind Mount&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td style=&quot;width: 31.6279%; height: 20px;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;호스트의 특정 경로&lt;/span&gt;를 컨테이너에 연결&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.7675%; height: 20px;&quot;&gt;&lt;span&gt;실시간 반영 가능, 유연성 높음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 28.7209%; height: 20px;&quot;&gt;&lt;span&gt;개발 중 코드 공유, 로그 확인&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 14.7674%; height: 20px;&quot;&gt;&lt;i&gt;&lt;span&gt;&lt;b&gt;tmpfs Mount&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td style=&quot;width: 31.6279%; height: 20px;&quot;&gt;&lt;span&gt;휘발성&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;메모리&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;공간에 저장&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.7675%; height: 20px;&quot;&gt;&lt;span&gt;고속 처리, 재부팅 시 데이터 삭제&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 28.7209%; height: 20px;&quot;&gt;&lt;span&gt;캐시, 인증 정보, 민감한 임시 데이터&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;각 방식은 내부 동작 방식도 다르고, 보안/성능/유연성 측면에서도 큰 차이가 있어요.&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: #3a4954; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;1. Volume (Docker Managed Volume)&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker가 직접 관리하는 특별한 디렉터리(&lt;i&gt;/var/lib/docker/volumes&lt;/i&gt;)에 데이터를 저장하는 방식이에요.&lt;/p&gt;
&lt;pre id=&quot;code_1754227658314&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;docker volume create mydata&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;i&gt;docker volume&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;명령은 Docker root dit(&lt;i&gt;/var/lib/docker&lt;/i&gt;) 영역에 volume 영역을 만들어 컨테이너 내부 경로와 연결(&lt;i&gt;mount&lt;/i&gt;)합니다.&lt;/blockquote&gt;
&lt;pre id=&quot;code_1754227658314&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;docker run -d \
  -v mydata:/var/lib/mysql \
  mysql:8.0&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;mydata는&amp;nbsp;도커가&amp;nbsp;&lt;i&gt;/var/lib/docker/volumes/mydata/_data&lt;/i&gt;에&amp;nbsp;저장돼요.&lt;/li&gt;
&lt;li&gt;컨테이너를 삭제해도 mydata 볼륨은 살아 있어서 데이터 유지 가능&lt;/li&gt;
&lt;li&gt;운영 환경에서 가장 많이 사용하는 방식입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  암시적 Volume 생성&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754227658314&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;docker run \
   -v /data \
   nginx&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;위처럼 volume 이름을 명시하지 않아도 위처럼&amp;nbsp;&lt;i&gt;-v some_path&lt;/i&gt;만 쓰면 Docker가 자동으로 무작위 이름의 Volume을 생성해요.&lt;/li&gt;
&lt;li&gt;단점은 이름이 랜덤이라 관리/식별이 불편해요. 때문에 직접 이름을 명시해서 생성하는 습관이 좋아요.&lt;/li&gt;
&lt;/ul&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: #3a4954; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;2. Bind Mount (호스트 경로 마운트)&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;호스트 머신의 디렉터리를 컨테이너에 그대로 연결하는 방식이에요.&lt;/p&gt;
&lt;pre id=&quot;code_1754227658315&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;docker run --rm \
  -v $(pwd)/html:/usr/share/nginx/html \
  nginx&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;&lt;i&gt;호스트의 절대 경로:컨테이너 내부 경로&lt;/i&gt;를 직접 마운트 하여 동기화&lt;/li&gt;
&lt;li&gt;실시간으로 변경사항 반영돼서 개발에 유용&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  기본 권한은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;rw&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;마운트 시 기본 권한은 읽기/쓰기(rw)예요.&lt;/li&gt;
&lt;li&gt;필요시 읽기 전용으로 설정할 수도 있어요.(컨테이너가 파일을 수정할 수 없음)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1754227658315&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;-v $(pwd)/html:/usr/share/nginx/html:ro&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;h3 style=&quot;color: #3a4954; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3. tmpfs Mount (메모리 기반 휘발성 저장)&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;디스크를 쓰지 않고, 호스트 메모리(RAM)에 데이터를 저장해요.&lt;/p&gt;
&lt;pre id=&quot;code_1754227658315&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;docker run --rm \
  --tmpfs /app/tmp:rw,size=64m \
  myapp&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;컨테이너 내부의&amp;nbsp;&lt;i&gt;/app/tmp&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;경로에 64MB 크기의 메모리 기반 파일 시스템을 마운트 하는 명령어&lt;/li&gt;
&lt;li&gt;&lt;i&gt;tmpfs&lt;/i&gt;는 리눅스 커널의 메모리 파일 시스템 기능을 활용하고, 컨테이너가 실행될 때 호스트 메모리를 직접 할당해 사용합니다.&lt;/li&gt;
&lt;li&gt;컨테이너가 종료 시 데이터도 함께 사라짐, 영구 저장이 목적이라면 사용하면 안 돼요.&lt;/li&gt;
&lt;li&gt;컨테이너 간의 공유 설정은 안되고, Linux 기반 Docker에서만 지원됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;  그렇다면 굳이 휘발성인데 tmpfs를 쓸까요?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디스크 대신 메모리 기반이기 때문에 빠른 처리가 가능&lt;/li&gt;
&lt;li&gt;민감한 데이터(세션, 인증 키 등)를 디스크에 남기지 않음&lt;/li&gt;
&lt;li&gt;캐시, 임시 파일 등 처리 후 바로 삭제해도 무방한 데이터에 적합&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  docker volume 예제&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 실전 예제 1: DB 데이터 유지&lt;/p&gt;
&lt;pre id=&quot;code_1754227658316&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;docker volume create mysql-data

docker run -d \
  --name mysql \
  -v mysql-data:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=1 \
  mysql:latest&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;&lt;i&gt;mysql-data&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;볼륨은 컨테이너 외부에 데이터 저장&lt;/li&gt;
&lt;li&gt;컨테이너를 삭제해도 데이터는 살아남음&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. 실전 예제 2: 개발 환경에서 코드 실시간 반영&lt;/p&gt;
&lt;pre id=&quot;code_1754227658316&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;docker run --rm -p 3000:80 \
  -v $(pwd)/my-site:/usr/share/nginx/html \
  nginx&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;로컬에서 수정한 코드가 바로 컨테이너에 반영돼요.&lt;/li&gt;
&lt;li&gt;개발 시 많이 사용되는 워크 플로우&lt;/li&gt;
&lt;/ul&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;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;다른 컨테이너의 볼륨 공유하는 법&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;--volumes-from&lt;/i&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;--volumes-from&lt;/i&gt;은 기존 컨테이너의 볼륨 설정을 그대로 복사해서 재사용하는 기능이에요.&lt;/p&gt;
&lt;pre id=&quot;code_1754227658317&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;docker run -d \
  --name dbdata \
  -v /data \
  busybox

docker run -it --rm \
  --volumes-from dbdata \
  ubuntu&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;dbdata의 볼륨(/data)을 새로운 컨테이너에서도 동일하게 사용 가능해요.&lt;/li&gt;
&lt;li&gt;여러 컨테이너가 같은 데이터를 접근해야 할 때 유용해요.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Docker</category>
      <category>Docker</category>
      <author>민팁(MINTIP)</author>
      <guid isPermaLink="true">https://yeo-computerclass.tistory.com/594</guid>
      <comments>https://yeo-computerclass.tistory.com/594#entry594comment</comments>
      <pubDate>Sun, 3 Aug 2025 22:47:59 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] 도커 네트워크 쉽게 끝내기</title>
      <link>https://yeo-computerclass.tistory.com/593</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  도커 네트워크를 왜 공부해야 할까?&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;도커를 막 배우기 시작하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;docker run&lt;/i&gt;만 알아도 컨테이너를 띄울 수 있어요. 단일 컨테이너로 간단한 실습을 할 땐 이걸로도 충분하죠.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 실제 서비스를 운영하려고 하면 곧 이런 의문들이 생기기 시작해요:&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;&quot;백엔드 컨테이너가 DB에 연결하려면?&quot;&lt;br /&gt;&amp;ldquo;외부 사용자가 내 서비스에 접속하려면 어떻게 하지?&amp;rdquo;&lt;br /&gt;&quot;컨테이너를 두 개 띄웠는데 어떻게 서로 통신하지?&quot;&lt;br /&gt;&quot;컨테이너 여러 개에 부하를 나누려면?&quot;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사실 이런 고민은 컨테이너를 하나만 실행할 때도 생겨요. 외부에서 접속하려면 포트를 열어야 하고, 외부 API나 DB에 연결하려면 DNS와 라우팅도 신경 써야 해요. 프록시나 보안 설정이 필요한 경우도 많고요. 결국 진짜 운영을 하려면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;도커 네트워크&lt;/i&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;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  도커 네트워크는 어떻게 구성돼 있을까?&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;도커 네트워크는 단순히 도커만의 기술이 아니에요.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;리눅스 커널&lt;/span&gt;이 제공하는 기능(Linux Networking)들&lt;/b&gt;&lt;span&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;922&quot; data-origin-height=&quot;574&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKxgBz/btsOu8oKnqp/BlEIfLuYuDz7nkkDx5rBWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKxgBz/btsOu8oKnqp/BlEIfLuYuDz7nkkDx5rBWK/img.png&quot; data-alt=&quot;출처:https://watch-n-learn.tistory.com/26&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKxgBz/btsOu8oKnqp/BlEIfLuYuDz7nkkDx5rBWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKxgBz%2FbtsOu8oKnqp%2FBlEIfLuYuDz7nkkDx5rBWK%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;922&quot; height=&quot;574&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;574&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처:https://watch-n-learn.tistory.com/26&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt; &amp;nbsp;Network Namespace &amp;ndash; 격리된 네트워크 공간&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;리눅스 커널은 namespace라는 기능을 통해, 컨테이너 하나하나가 독립된 공간처럼 동작하도록 만들어줘요. 그중&amp;nbsp;&lt;i&gt;network namespace&lt;/i&gt;는 컨테이너마다 자신만의 네트워크 공간을 만들어요. 즉, 각자 별도의 IP 주소, 라우팅 테이블, 네트워크 인터페이스를 가지게 되는 거죠.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 각 컨테이너는 서로 완전히 격리되어 있고, 자기만의&amp;nbsp;&lt;i&gt;eth0&lt;/i&gt;,&amp;nbsp;&lt;i&gt;lo&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은 인터페이스를 갖게 돼요.&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt; &lt;i&gt;ip netns list&lt;/i&gt;,&amp;nbsp;&lt;i&gt;ip netns exec&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;명령어로 리눅스에서도 네트워크 namespace를 확인할 수 있어요.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt; &amp;nbsp;veth pair &amp;ndash; 가상의 이더넷 인터페이스&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;veth(Virtual Ethernet)&lt;/i&gt;는 컨테이너와 호스트 네트워크를 연결하는 가상의 네트워크 케이블이에요.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한쪽은 컨테이너 내부의&amp;nbsp;&lt;i&gt;eth0&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;다른 한쪽은 도커 호스트의&amp;nbsp;&lt;i&gt;Linux Bridge(docker0)&lt;/i&gt;에 연결돼요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 해서&amp;nbsp;&lt;b&gt;컨테이너와 호스트 네트워크가 이어지는 통로가 생기는 거예요.&lt;/b&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt; &amp;nbsp;&lt;i&gt;docker exec &amp;lt;컨테이너&amp;gt; ip addr show eth0&lt;/i&gt;을 실행하면&amp;nbsp;&lt;i&gt;eth0@ifX&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같이 연결된 veth 인터페이스 정보를 볼 수 있어요.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt; &amp;nbsp;Linux Bridge(&lt;i&gt;docker0&lt;/i&gt;) &amp;ndash; 컨테이너끼리 통신을 가능하게 하는 가상의 스위치&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;Linux Bridge&lt;/i&gt;는 리눅스에서 제공하는 가상의 네트워크 스위치예요. 도커는 기본적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;docker0&lt;/i&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;하지만 컨테이너가 직접 브리지에 연결되지 않고, 컨테이너 내부&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;eth0&lt;/i&gt;은 veth를 통해 브리지에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;간접적으로 연결&lt;/b&gt;돼요.&lt;/p&gt;
&lt;pre id=&quot;code_1753420790490&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;[컨테이너 eth0] &amp;harr; [vethA] &amp;harr; [vethB] &amp;harr; [Linux Bridge: docker0]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 브리지에 연결된 컨테이너들은 마치 같은 공유기에 연결된 장치들처럼 서로 자유롭게 통신할 수 있어요.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;또한 브리지는 호스트의 실제 네트워크 인터페이스(예:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;eth0&lt;/i&gt;)와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;iptables(NAT)&lt;/i&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;i&gt;172.17.0.0/16&lt;/i&gt;이라는 프라이빗 IP 대역을 사용해 컨테이너에 IP를 부여해요. 사용자 정의 브리지를 만들면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;192.168.0.0/20&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;또는&amp;nbsp;&lt;i&gt;172.18.0.0/16&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은 범위를 자동으로 설정해 줘요.&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt; &amp;nbsp;&lt;i&gt;brctl show&lt;/i&gt;로 docker0 브리지에 연결된 veth 인터페이스들을 확인할 수 있어요.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt; &amp;nbsp;iptables &amp;ndash; 외부와의 연결을 제어하는 방화벽이자 라우터&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;컨테이너가 외부와 통신하려면, 단순히 브리지에 연결하는 것만으로 부족해요. 리눅스 커널은 '패킷이 어디에서 왔고, 어디로 가야 하는지'를 결정할 수단이 필요한데, 그걸 담당하는 게 바로&amp;nbsp;&lt;i&gt;iptables&lt;/i&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;&lt;i&gt;iptable&lt;/i&gt;는 원래 리눅스의 방화벽 겸 트래픽 라우팅 도구로, 도커에서는 이를 활용해 다음 두 가지 주요 기능을 수행해요:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;DNAT (Destination NAT)&lt;/b&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부에서 특정 포트(예: 8080)로 들어오는 요청을, 실제 내부 컨테이너의 IP와 포트(예: 172.17.0.2:80)로 바꿔줘요.&lt;/li&gt;
&lt;li&gt;예를 들어,&amp;nbsp;&lt;i&gt;localhost:8080&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;컨테이너_IP:80&lt;/i&gt;&lt;br /&gt;&lt;i&gt;localhost:8080&lt;/i&gt;으로 접속하면 커널은 이 요청을 iptables를 통해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;다른 목적지 IP/포트로 전환(Destination Network&amp;nbsp;Address&amp;nbsp;Translation)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;시켜요.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SNAT (Source NAT 또는 MASQUERADE)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너에서 외부로 나갈 때 IP를 호스트의 IP로 바꿔줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 해서&amp;nbsp;&lt;b&gt;컨테이너는 마치 호스트인 척하면서 외부와 통신&lt;/b&gt;할 수 있고, 외부에서 오는 요청도&amp;nbsp;&lt;b&gt;마치 호스트에 도달한 것처럼 보이지만 실제로는 컨테이너로 연결&lt;/b&gt;돼요.&lt;/p&gt;
&lt;pre id=&quot;code_1753420790491&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;iptables -t nat -L -n&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&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;NAT(DNAT, SNAT)&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;규칙을 확인할 수 있어요.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt; &amp;nbsp;CNM (Container Network Model) &amp;ndash; 도커 네트워크의 내부 설계도&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;도커는 위의 모든 리눅스 네트워크 기능을 잘 추상화해서 관리하는 아키텍처를 만들었어요. 그게 바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;CNM(Container Network Model)&lt;/i&gt;이에요. 도커가&amp;nbsp;&lt;b&gt;컨테이너 하나의 네트워크 환경을 만들고 네트워크에 연결하고 트래픽을 주고받는 모든 과정을 추상화한 구조&lt;/b&gt;예요.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;CNM은 안에서 도커는 다음과 같은 단위로 네트워크를 조립해요:&lt;/p&gt;
&lt;table style=&quot;color: #000000; text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot; data-ke-align=&quot;alignLeft&quot; data-pm-slice=&quot;3 3 []&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.9767%;&quot;&gt;&lt;b&gt;&lt;span&gt;구성 요소&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 82.907%;&quot;&gt;&lt;b&gt;&lt;span&gt;설명&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.9767%;&quot;&gt;&lt;span&gt;&lt;b&gt;Sandbox&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 82.907%;&quot;&gt;&lt;span&gt;컨테이너의 network namespace와 그 안의 인터페이스(&lt;i&gt;eth0&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;등)를 포함하는 공간. 독립적인 네트워크 환경을 구성&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.9767%;&quot;&gt;&lt;span&gt;&lt;b&gt;Endpoint&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 82.907%;&quot;&gt;&lt;span&gt;veth의 한쪽처럼 네트워크와 연결되는 접점&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.9767%;&quot;&gt;&lt;span&gt;&lt;b&gt;Network&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 82.907%;&quot;&gt;&lt;span&gt;여러 Endpoint가 붙는 논리적 네트워크 단위 (예: bridge network, overlay network)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.9767%;&quot;&gt;&lt;span&gt;&lt;b&gt;Driver&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 82.907%;&quot;&gt;실제 네트워크 기술을 사용하는 모듈 (bridge, host, overlay 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;  Overlay 네트워크란?&lt;/b&gt;&lt;br /&gt;Overlay 네트워크는 여러 대의 서버(호스트)에 흩어져 있는 컨테이너들끼리 마치 한 대의 서버 안에 있는 것처럼 통신할 수 있도록 만들어주는 가상의 네트워크예요. 일반적으로 도커 Swarm이나 Kubernetes 같은 클러스터 환경에서 사용되고, 서버 간 통신은 VXLAN이라는 기술로 터널링 돼요.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;도커는 이 구조를 바탕으로 아래와 같은 명령어 하나로 복잡한 네트워크 구성을 아주 쉽게 만들어줘요:&lt;/p&gt;
&lt;pre id=&quot;code_1753420790492&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;docker network create --driver bridge my-network
docker run --net=my-network ...&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;결국 CNM은 리눅스 네트워크 기술들을 도커 사용자에게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;쉽고 일관되게 제공하기 위한 추상화 계층&lt;/b&gt;이에요. 도커는 네임스페이스 생성, veth 연결, 브리지 설정, iptables 구성까지 모든 걸 알아서 해주지만, 그 이면에는 이 구조가 작동하고 있는 거예요.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;docker network&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;명령어&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  네트워크 목록 보기&lt;/h3&gt;
&lt;pre id=&quot;code_1753420790492&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;docker network ls&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  네트워크 생성 및 주요 옵션&lt;/h3&gt;
&lt;pre id=&quot;code_1753420790492&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;docker network create [OPTIONS] NETWORK_NAME&lt;/code&gt;&lt;/pre&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 157px;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot; data-ke-align=&quot;alignLeft&quot; data-pm-slice=&quot;3 3 []&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 21.7442%;&quot;&gt;&lt;b&gt;&lt;span&gt;옵션&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 78.1396%;&quot;&gt;&lt;b&gt;&lt;span&gt;설명&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 21.7442%;&quot;&gt;&lt;i&gt;&lt;span&gt;--driver&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 78.1396%;&quot;&gt;&lt;span&gt;사용할 네트워크 드라이버 지정&lt;br /&gt;&lt;br /&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;bridge&lt;/u&gt;: 컨테이너들 간의 통신이 가능하고, 호스트와도 통신 가능한 격리퇴 네트워크&lt;br /&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;host&lt;/u&gt;: 격리 없이 호스트 네트워크 그대로 사용&lt;br /&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;none&lt;/u&gt;: 네트워크에 접속하지 않음. 무지정(격리용)&lt;br /&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;overlay&lt;/u&gt;: Swarm 전용, 여러 호스트 간 네트워크&lt;br /&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;macvlan&lt;/u&gt;: 실제 NIC처럼 동작하도록 만듦 (고급 사용)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 21.7442%;&quot;&gt;&lt;i&gt;&lt;span&gt;--subnet&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 78.1396%;&quot;&gt;&lt;span&gt;사용자 지정 서브넷 지정 (예:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;192.168.100.0/24&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 21.7442%;&quot;&gt;&lt;i&gt;&lt;span&gt;--gateway&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 78.1396%;&quot;&gt;&lt;span&gt;네트워크의 게이트웨이 IP 지정. 이 주소는 컨테이너가 외부와 통신할 때 출입구 역할을 하는 IP. 일반적으로 서브넷의 첫 번째 IP를 사용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 21.7442%;&quot;&gt;&lt;i&gt;&lt;span&gt;--ip-range&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 78.1396%;&quot;&gt;&lt;span&gt;컨테이너에 할당될 수 있는 IP 범위 제한&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 21.7442%;&quot;&gt;&lt;i&gt;&lt;span&gt;--internal&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 78.1396%;&quot;&gt;&lt;span&gt;외부 통신을 차단한 내부 네트워크로 설정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;height: 21px; width: 21.7442%;&quot;&gt;&lt;i&gt;&lt;span&gt;--attachable&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td style=&quot;height: 21px; width: 78.1396%;&quot;&gt;&lt;span&gt;컨테이너가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;docker run --network&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;옵션으로 네트워크에 동적으로 연결 가능하게 설정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;height: 10px; width: 21.7442%;&quot;&gt;&lt;i&gt;&lt;span&gt;--label&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td style=&quot;height: 10px; width: 78.1396%;&quot;&gt;&lt;span&gt;네트워크에 메타 정보를 라벨로 추가&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예시:&lt;/p&gt;
&lt;pre id=&quot;code_1753420790493&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;docker network create \
  --driver=bridge \
  --subnet=192.168.100.0/24 \
  --gateway=192.168.100.1 \
  my-network&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;&lt;i&gt;docker0&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;기본 브리지 말고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;my-network&lt;/i&gt;라는 이름의 격리된 가상 네트워크가 하나 더 생깁니다.&lt;/li&gt;
&lt;li&gt;여기에 컨테이너를 붙이면 자동으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;192.168.100.x&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;대역에서 IP를 받아요.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;192.168.100.1&lt;/i&gt;은 게이트웨이로 지정되어 컨테이너가 외부랑 통신 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;  언제 이렇게 사용할까?&lt;/b&gt;&lt;br /&gt;&lt;u&gt;1. 네트워크 충돌을 방지&lt;/u&gt;&lt;br /&gt;기본 도커 네트워크는 172.17.x.x 등을 자동 할당해요. 이미 그 대역을 다른 네트워크에서 사용하고 있다면 충돌이 발생할 수 있어요. 직접 서브넷을 지정하면 이런 문제를 피할 수 있어요.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;2. 예측 가능한 네트워크 구성&lt;/u&gt;&lt;br /&gt;개발/운영 환경에서 동일한 IP구조를 유지하고 싶을 때 유리해요. IP 기반 방화벽, 프록시, 로깅 시스템 연동이 쉬워져요.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;3. 멀티-컨테이너 시스템에서 네트워크 분리&lt;/u&gt;&lt;br /&gt;예: DB와 백엔드만 통신 가능하게 하고 싶을 때 &amp;rarr; 같은 네트워크에 묶어서 접근 가능하게 설정&lt;br /&gt;&lt;br /&gt;&lt;u&gt;4. 자동 DNS 지원&lt;/u&gt;&lt;br /&gt;컨테이너 이름으로 통신할 수 있어어 IP 몰라도 되고, 환경마다 바뀌는 IP에 일일이 대응할 필요가 없어요.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;5. 보안 격리&lt;/u&gt;&lt;br /&gt;네트워크 단위로 서비스 그룹을 격리할 수 있어 보안성 향상과 관리 효율성을 얻을 수 있어요. (bridge, host, overlay 등)&lt;/blockquote&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;예: 컨테이너 실행 시 네트워크 지정&lt;/h4&gt;
&lt;pre id=&quot;code_1753420790494&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;docker run -d \
  --name my-app \
  --network my-network \
  nginx:latest&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 하면 nginx 컨테이너는&amp;nbsp;&lt;i&gt;192.169.100.x&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;대역의 IP를 자동 할당받고, 게이트웨이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;192.168.100.1&lt;/i&gt;을 통해 외부와 통신할 수 있어요.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  네트워크 상세 정보 확인&lt;/h3&gt;
&lt;pre id=&quot;code_1753420790494&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;docker network inspect my-network&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;해당 네트워크에 연결된 컨테이너, 각 컨테이너의 IP 정보, subnet, gateway 등을 볼 수 있어요.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  네트워크 삭제&lt;/h3&gt;
&lt;pre id=&quot;code_1753420790494&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;docker network rm my-network&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;연결된 컨테이너가 없을 때만 삭제할 수 있어요.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  네트워크 추가 연결/분리하기&lt;/h3&gt;
&lt;pre id=&quot;code_1753420790494&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;docker network connect|disconnect my-network my-app&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;b&gt;다른 네트워크를 추가로 연결하거나 분리&lt;/b&gt;할 수 있어요. 이 기능은 컨테이너가 복수의 네트워크에 연결되어 있어야 할 때, 특히 보안 구역을 나누거나 다양한 서비스와 독립적으로 통신할 때 유용하게 사용돼요.&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;  컨테이너를 처음 생성할 때&amp;nbsp;&lt;i&gt;--network&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;옵션으로 하나의 네트워크만 지정할 수 있어요.&lt;br /&gt;&lt;b&gt;여러 네트워크에 연결하려면&amp;nbsp;&lt;i&gt;docker network connect&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;명령어를 추가로 사용&lt;/b&gt;해야 해요.&lt;br /&gt;+ 아니면&amp;nbsp;&lt;i&gt;docker-compose.yml&lt;/i&gt;에서&amp;nbsp;&lt;i&gt;networks&lt;/i&gt;를 여러 개 지정하는 방식으로 해야 해요.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예시:&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;frontend&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;컨테이너는 외부 요청을 받아야 하기에&amp;nbsp;&lt;i&gt;public-net&lt;/i&gt;에 연결되어 있는 상태. 그런데 내부 서비스인&amp;nbsp;&lt;i&gt;backend&lt;/i&gt;와도 통신해야 해서,&amp;nbsp;&lt;i&gt;private-net&lt;/i&gt;에도 연결되어야 하는 상황&lt;/p&gt;
&lt;pre id=&quot;code_1753420790494&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;docker network connect private-net frontend&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;i&gt;frontend&lt;/i&gt;는&amp;nbsp;&lt;i&gt;public-net&lt;/i&gt;에만 있었지만, 이제&amp;nbsp;&lt;i&gt;private-net&lt;/i&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;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  도커 DNS&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;도커는 사용자 정의 네트워크를 만들면 자동으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;내부 DNS 서버&lt;/b&gt;를 생성해줘요. 덕분에 컨테이너 이름만으로 통신이 가능해요.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너가 사용자 정의 네트워크에 연결되면, 도커 내부 DNS 서버가 컨테이너 이름을 자동으로 IP 매핑해 줘요.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;/etc/hosts&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;설정 없이도 동작하며, 컨테이너 이름이 DNS 도메인처럼 작동해요.&lt;/li&gt;
&lt;li&gt;이 기능은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;기본 bridge 네트워크에서는 동작하지 않고, 사용자 정의 네트워크에서만 가능&lt;/b&gt;해요.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1753420790495&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;ping my-app
curl http://my-app:3000&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;위 명령어는&amp;nbsp;&lt;i&gt;my-app&lt;/i&gt;라는 이름을 가진 컨테이너의 IP를 자동으로 찾아 통신하는 예예요.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;즉, 네트워크 생성하는 것은 단순한 IP 연결만 제공하는 게 아니라,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;DNS 기반 서비스 검색(Discovery) 기능까지 기본 내장&lt;/b&gt;돼 있는 강력한 구성 방식에요. 덕분에 컨테이너 이름만으로 통신이 가능해요.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  --net-alias: 컨테이너에 또 다른 이름을 붙여주는 옵션&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;도커는 사용자 정의 네트워크를 만들면 컨테이너 이름으로 DNS 통신이 가능해져요. 즉, 컨테이너 이름만 알면 IP를 몰라도 아래처럼 바로 통신할 수 있죠.&lt;/p&gt;
&lt;pre id=&quot;code_1753420790495&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;curl http://my-app&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;i&gt;--net-alias&lt;/i&gt;예요. 아래와 같이 설명하면, 해당 컨테이너는 원래 이름 외에 backend라는&amp;nbsp;&lt;i&gt;별칭&lt;/i&gt;으로도 통신할 수 있게 돼요.&lt;/p&gt;
&lt;pre id=&quot;code_1753420790495&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;docker run --net-alias backend ...&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;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;  언제 alias가 필요할까?&lt;br /&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&quot;컨테이너에 이름(--name)을 주면 DNS로 접근이 가능한데 굳이 --net-alias가 왜 필요한 거지?&quot;라는 의문점이 들 수 있어요. 아래와 같은 상황에서 --net-alias는 사용됩니다.&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;b&gt;1. 여러 컨테이너를 같은 이름으로 접근하고 싶을 때 (예: 로드밸런싱)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;--name은 컨테이너마다 반드시 교유해야 하기 때문에, 컨테이너 2개를 띄워도 이름은 다르게 줘야 해요.&lt;/p&gt;
&lt;pre id=&quot;code_1753420790495&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;docker run -d --name backend1 --network my-net my-app
docker run -d --name backend2 --network my-net my-app&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;&lt;b&gt;nginx.conf&lt;/b&gt;(--name만 사용하는 경우):&lt;/p&gt;
&lt;pre id=&quot;code_1753420790495&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;upstream backend {
  server backend1:3000;
  server backend2:3000;
}

server {
  listen 80;
  location / {
    proxy_pass http://backend;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;⚠️ Nginx에서 로드밸런서를 구성하려면 각 컨테이너의 실제 이름 또는 IP를 모두 적어줘야 해요. 또한 컨테이너를 추가하거나 삭제할 때마다 nginx.conf를 고쳐야 하고 IP가 바뀌면 또다시 수정해야 하죠.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이제&amp;nbsp;&lt;i&gt;--net-alias&lt;/i&gt;를 사용해 볼게요:&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753420790495&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;docker run -d --name backend1 --network my-net --net-alias backend my-app
docker run -d --name backend2 --network my-net --net-alias backend my-app&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 위 두 컨테이너는 backend1, backend2라는 이름은 각각 다르지만, 공통적으로 backend라는&amp;nbsp;&lt;b&gt;alias&lt;/b&gt;를 가지고 있어요.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;도커는 같은 alias를 가진 컨테이너가 여러 개인 경우,&amp;nbsp;&lt;b&gt;내부 DNS에서 라운드로빈 방식으로 IP를 분산해서 응답해 줍니다.&lt;/b&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;  도커의 DNS 라운드로빈이란?&lt;/b&gt;&lt;br /&gt;도커는 하나의 alias에 여러 컨테이너가 연결되어 있으면, DNS 질의에 대해 등록된 IP 목록을 번갈아 응답해요.&lt;br /&gt;
&lt;pre id=&quot;code_1753420790496&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;curl http://backend
# &amp;rarr; backend1의 IP로 요청
curl http://backend
# &amp;rarr; 이번엔 backend2의 IP로 요청&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;✔️ Nginx가 내부 DNS에 backend 이름을 질의할 때마다, 컨테이너 IP가 돌아가면서 응답되기 때문에, 별도 로드밸런서 없이도 트래픽이 자동 분산됩니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;nginx.conf&lt;/b&gt;(--net-alias를 사용하는 경우):&lt;/p&gt;
&lt;pre id=&quot;code_1753420790496&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;upstream backend {
  server backend:3000;
}

server {
  listen 80;
  location / {
    proxy_pass http://backend;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;이제 nginx.conf에는 alias 하나만 쓰면 자동으로 분산 처리가 됩니다. 컨테이너가 몇 개든 --net-alias backend만 잘 붙여주면 설정은 그대로 유지돼요.&lt;/blockquote&gt;</description>
      <category>Docker</category>
      <author>민팁(MINTIP)</author>
      <guid isPermaLink="true">https://yeo-computerclass.tistory.com/593</guid>
      <comments>https://yeo-computerclass.tistory.com/593#entry593comment</comments>
      <pubDate>Fri, 25 Jul 2025 14:20:22 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] 도커 컨테이너 완벽 가이드: 개념부터 명령어, 실전 활용까지</title>
      <link>https://yeo-computerclass.tistory.com/592</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  컨테이너란?&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker에서 컨테이너는&amp;nbsp;&lt;b&gt;이미지를 실행한 결과물&lt;/b&gt;이에요.&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;이미지(Image) = 실행 전의 정적인 템플릿&lt;br /&gt;컨테이너(Container) = 실행 중인 동적인 인스턴스&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;컨테이너는 다음과 같은 특징을 가져요:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이식성: 동일한 환경을 어디서나 재현 가능&lt;/li&gt;
&lt;li&gt;경량성: 호스트 OS의 커널을 공유하므로 VM보다 경량&lt;/li&gt;
&lt;li&gt;빠른 실행: 수 초 내로 부팅 및 종료 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;도커 컨테이너는 &amp;ldquo;애플리케이션 + 실행환경&amp;rdquo;을 하나로 묶어, 기술적으로는&amp;nbsp;&lt;b&gt;리눅스 커널 위에서 작동하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;프로세스&lt;/b&gt;&lt;/span&gt;지만, 외부와&amp;nbsp;&lt;b&gt;격리된 파일 시스템, 네트워크, 환경변수&amp;nbsp;&lt;/b&gt;등을 갖고 있어 독립된 애플리케이션처럼 작동해요.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  컨테이너를 실행하는 법:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;docker run&lt;/i&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;가장 많이 사용하는 명령어는 바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;docker run&lt;/i&gt;이에요.&lt;/p&gt;
&lt;pre id=&quot;code_1753420728551&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;docker run [OPTIONS] IMAGE [COMMAND]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예시:&lt;/p&gt;
&lt;pre id=&quot;code_1753420728551&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;$ docker run --name myweb nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 한 줄 명령어는 사실 다음 3가지 동작을 순차적으로 실행해요.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이미지 존재 여부 확인 &amp;rarr; 없다면 Docker Hub에서 자동으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;pull&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;컨테이너 생성(&lt;i&gt;docker create&lt;/i&gt;): 이미지 기반으로 컨테이너 만들기&lt;/li&gt;
&lt;li&gt;컨테이너 시작(&lt;i&gt;docker start&lt;/i&gt;): 생성한 컨테이너 실행하기&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;즉,&amp;nbsp;&lt;i&gt;docker run&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;=&amp;nbsp;&lt;i&gt;pull&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;+&amp;nbsp;&lt;i&gt;create&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;+&amp;nbsp;&lt;i&gt;start&lt;/i&gt;의 모든 기능을 포함한 명령어입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1753420728552&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;# 예시: 개별 명령어로 실행
$ docker pull nginx
$ docker create --name myweb nginx
$ docker start myweb&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;  CI/CD 환경이나 운영에서 정확한 흐름을 통제하려면&amp;nbsp;&lt;i&gt;create&lt;/i&gt;와&amp;nbsp;&lt;i&gt;start&lt;/i&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;docker run 자주 쓰는 옵션들&lt;/h3&gt;
&lt;table style=&quot;color: #000000; text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot; data-ke-align=&quot;alignLeft&quot; data-pm-slice=&quot;3 3 []&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;&lt;span&gt;옵션&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;&lt;span&gt;설명&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i&gt;&lt;span&gt;--name myapp&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;컨테이너에 이름 설정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i&gt;&lt;span&gt;-d&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;백그라운드 모드로 실행 (detach 모드)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i&gt;&lt;span&gt;-it&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;터미널을 연결 (interactive + TTY)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i&gt;&lt;span&gt;--rm&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;컨테이너 종료 후 자동 삭제 (테스트용으로 좋음)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i&gt;&lt;span&gt;-p 8080:80&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;포트 바인딩 (호스트:컨테이너)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i&gt;&lt;span&gt;-v ~/data:/app/data&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;볼륨 마운트로 호스트 디렉터리 연결&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i&gt;&lt;span&gt;--env MODE=dev&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;컨테이너에 환경 변수 주입&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i&gt;&lt;span&gt;--network&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;컨테이너가 연결될 네트워크 지정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i&gt;&lt;span&gt;--cpus=0.5&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;CPU 자원 제한&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i&gt;&lt;span&gt;--memory=512m&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;메모리 자원 제한&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre id=&quot;code_1753420728553&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;# 예시
$ docker run -d --name web -p 8080:80 nginx
$ docker run --rm -it ubuntu:22.04 /bin/bash&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;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  Docker 컨테이너 Lifecycle (생명주기)&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker 컨테이너는 여러 상태를 오가며 동작해요:&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;&lt;span&gt;상태&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;설명&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;&lt;span&gt;명령어&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;생성 (Created)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;create&lt;/span&gt;로 생성만 된 상태&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;i&gt;&lt;span&gt;docker create&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;실행 (Running)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;실제 실행 중인 상태&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;i&gt;&lt;span&gt;docker start&lt;/span&gt;&lt;/i&gt;&lt;span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;i&gt;&lt;span&gt;docke run&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;일시 정지 (Paused)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;CPU 사용 중지됨&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;i&gt;&lt;span&gt;docker pause&lt;/span&gt;&lt;/i&gt;&lt;span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;i&gt;&lt;span&gt;docker unpause&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;종료 (Exited)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;정상/비정상 종료&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;i&gt;&lt;span&gt;docker stop&lt;/span&gt;&lt;/i&gt;&lt;span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;i&gt;&lt;span&gt;docker kill&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;삭제 (Removed)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;컨테이너 자체 삭제&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;i&gt;&lt;span&gt;docker rm&lt;/span&gt;&lt;/i&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre id=&quot;code_1753420728553&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;$ docker create [OPTIONS] IMAGE [COMMAND]     # 컨테이너 생성
$ docker start [OPTIONS] CONTAINER            # 정지된 컨테이너 시작
$ docker stop [OPTIONS] CONTAINER             # 실행 중인 컨테이너 정상 종료 (SIGTERM)
$ docker kill [OPTIONS] CONTAINER             # 즉시 종료 (SIGKILL)
$ docker restart [OPTIONS] CONTAINER          # 컨테이너 재시작
$ docker pause CONTAINER                      # CPU 사용 중지 (정지 상태)
$ docker unpause CONTAINER                    # 정지된 컨테이너 재개
$ docker rm [OPTIONS] CONTAINER               # 컨테이너 삭제&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;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  컨테이너 관련 명령어 정리&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;✅ 컨테이너 생성과 실행&lt;/h3&gt;
&lt;pre id=&quot;code_1753420728554&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;$ docker pull ubuntu                   # 이미지 다운로드
$ docker create --name test ubuntu     # 컨테이너 생성
$ docker start test                    # 컨테이너 실행
$ docker run -it --rm ubuntu bash      # 실행 + 인터랙티브 + 종료 시 삭제&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;✅ 상태 확인 및 프로세스&lt;/h3&gt;
&lt;pre id=&quot;code_1753420728554&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;$ docker ps                            # 실행 중인 컨테이너 목록
$ docker ps -a                         # 모든 컨테이너 목록 (종료 포함)
$ docker inspect myweb                 # 상세 정보 (IP주소, mount 정보 등 JSON 형식)
$ docker top myweb                     # 컨테이너 내부 프로세스 확인
$ docker stats                         # 실시간 리소스 사용량&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;✅ 컨테이너 접속 및 명령 실행&lt;/h3&gt;
&lt;pre id=&quot;code_1753420728554&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;$ docker exec -it myweb /bin/bash     # 쉘로 접속
$ docker exec myweb ls /app           # 컨테이너 내에서 명령 실행&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;✅ 로그 및 상태&lt;/h3&gt;
&lt;pre id=&quot;code_1753420728554&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;$ docker logs myweb
$ docker logs -f myweb                # 실시간 로그
$ docker inspect -f '{{.State.ExitCode}}' myweb&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;✅ 정지, 삭제, 재시작&lt;/h3&gt;
&lt;pre id=&quot;code_1753420728554&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;$ docker stop myweb                   # 정상 종료 (SIGTERM)
$ docker kill myweb                   # 강제 종료 (SIGKILL)
$ docker pause myweb                  # 일시 정지
$ docker unpause myweb                # 일시 정지 해제
$ docker restart myweb                # 재시작
$ docker rm myweb                     # 컨테이너 삭제&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;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  변경사항 추적 및 이미지화&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;변경 내용 확인&lt;/h3&gt;
&lt;pre id=&quot;code_1753420728555&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;$ docker diff myweb                   # 파일시스템 변경 사항&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;b&gt;추가(A), 수정(M), 삭제(D) 되었는지를 보여줘요.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 결과를 통해 컨테이너 실행 중 어떤 파일이 바뀌었는지 알 수 있기 때문에, 테스트 중 변경된 설정 파일이나 로그 등을 추적할 때 유용해요.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;새로운 이미지 생성&lt;/h3&gt;
&lt;pre id=&quot;code_1753420728555&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;$ docker commit myweb myimage:latest&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;i&gt;commit&lt;/i&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;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  컨테이너 백업 및 복원&lt;/h2&gt;
&lt;pre id=&quot;code_1753420728555&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;# 컨테이너 백업 (파일 시스템만 저장)
$ docker export myweb &amp;gt; backup.tar

# tar 파일로부터 새로운 이미지 생성
$ docker import backup.tar newimage:1.0&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;i&gt;export&lt;/i&gt;/&lt;i&gt;import&lt;/i&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이미지의 레이어 구조와 메타데이터를 유지하지 않습니다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;단순히 파일 시스템만 유지합니다.&lt;/blockquote&gt;</description>
      <category>Docker</category>
      <category>Docker</category>
      <author>민팁(MINTIP)</author>
      <guid isPermaLink="true">https://yeo-computerclass.tistory.com/592</guid>
      <comments>https://yeo-computerclass.tistory.com/592#entry592comment</comments>
      <pubDate>Fri, 25 Jul 2025 14:19:19 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] 도커 이미지가 뭔데? 개념, 명령어, 계층 구조 완전 정리</title>
      <link>https://yeo-computerclass.tistory.com/591</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Docker Image란 무엇인가요?&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker에서&amp;nbsp;&lt;i&gt;이미지(Image)&lt;/i&gt;란 컨테이너를 만들기 위한 실행 환경을 패키징 한 파일이에요.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도커 이미지(docker image) = 실행 환경 + 애플리케이션 + 설정이 담긴 설계도&lt;/li&gt;
&lt;li&gt;이 이미지를 기반으로 만들어지는 것이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;컨테이너&lt;/i&gt;예요.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;예를 들어&amp;nbsp;&lt;i&gt;nginx&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;웹 서버를 실행하고 싶다면?&amp;nbsp;&lt;i&gt;nginx 이미지&lt;/i&gt;만 있으면 바로 컨테이너로 실행할 수 있어요. 설치 과정이 필요 없습니다.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;☁️ Docker Hub란?&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker Hub는 Docker 공식 이미지 저장소로, 전 세계 개발자들이 이미지를 공유하고 다운 로드할 수 있는&amp;nbsp;&lt;b&gt;공개 클라우드 레지스트리&lt;/b&gt;입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주소:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://hub.docker.com/&quot;&gt;https://hub.docker.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;수많은 공식 이미지 및 커뮤니티 이미지가 올라와 있어요.&lt;/li&gt;
&lt;li&gt;누구나 계정을 만들어 이미지를 업로드하거나 공유할 수 있어요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;흔히 사용하는&amp;nbsp;&lt;i&gt;docker pull ubuntu&lt;/i&gt;,&amp;nbsp;&lt;i&gt;docker pull nginx&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은 명령어는 Docker Hub에서 이미지를 가져오는 동작이에요.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker Hub의 역할은 GitHub의 코드 저장소와 비슷하게, 이미지를 업로드하고 내려받을 수 있는 중앙 저장소라고 보면 됩니다.&lt;/p&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;  Docker Hub에서도&amp;nbsp;&lt;b&gt;Private Repository&lt;/b&gt;를 만들 수 있어, 외부에 노출되지 않는 비공개 이미지 저장도 가능합니다.&lt;br /&gt;&lt;br /&gt;  Docker 이미지는 꼭 Docker Hub에만 저장해야 하는 것은 아니에요. 기업이나 팀에서는 보안, 속도, 내부 정책 문제로 인해&amp;nbsp;&lt;br /&gt;&lt;b&gt;다양한 컨테이너 이미지 레지스트리(Container Regsitry)&lt;/b&gt;를 사용하기도 합니다. (&lt;i&gt;Google Artifact Registry(GCP)&lt;/i&gt;,&amp;nbsp;&lt;i&gt;GitHub Container Registry&lt;/i&gt;,&amp;nbsp;&lt;i&gt;Amazon ECR&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;등)&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Docker Image 관련 명령어&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  이미지 검색&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker Hub에서 제공하는 공식 이미지를 검색하는 명령어예요. (Docker Hub 사이트에서도 확인할 수 있어요)&lt;/p&gt;
&lt;pre id=&quot;code_1752648560555&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;docker search [이미지이름]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예시:&lt;/p&gt;
&lt;pre id=&quot;code_1752648560556&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;docker search nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예시 출력:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;769&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RB3yn/btsOslWpG6p/M8ByT0KYv0TmSNvF86hPf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RB3yn/btsOslWpG6p/M8ByT0KYv0TmSNvF86hPf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RB3yn/btsOslWpG6p/M8ByT0KYv0TmSNvF86hPf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRB3yn%2FbtsOslWpG6p%2FM8ByT0KYv0TmSNvF86hPf0%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;769&quot; height=&quot;242&quot; data-origin-width=&quot;769&quot; data-origin-height=&quot;242&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;i&gt;NAME&lt;/i&gt;: 이미지 이름&lt;/li&gt;
&lt;li&gt;&lt;i&gt;DESCRIPTION&lt;/i&gt;: 설명&lt;/li&gt;
&lt;li&gt;&lt;i&gt;STARS&lt;/i&gt;: 좋아요 수 (커뮤니티 신뢰도)&lt;/li&gt;
&lt;li&gt;&lt;i&gt;OFFICIAL&lt;/i&gt;: 공식 인증 여부&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  이미지 다운로드 (pull)&lt;/h3&gt;
&lt;pre id=&quot;code_1752648560556&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;docker pull [이미지이름[:태그]]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예시:&lt;/p&gt;
&lt;pre id=&quot;code_1752648560556&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;docker pull ubuntu:22.04
docker pull node:18-alpine
docker pull redis:latest
docker pull nginx&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;&lt;i&gt;:태그&lt;/i&gt;를 생략하면 기본값이&amp;nbsp;&lt;i&gt;latest&lt;/i&gt;가 자동으로 붙어요.(최신 버전)&lt;/li&gt;
&lt;li&gt;명확한 환경 재현을 위해선 버전을 지정하는 것이 좋아요 (&lt;i&gt;ubuntu:22.04&lt;/i&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  현재 로컬에 있는 이미지 목록 확인&lt;/h3&gt;
&lt;pre id=&quot;code_1752648560556&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;docker images&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예시 출력:&lt;/p&gt;
&lt;pre id=&quot;code_1752648560556&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;REPOSITORY       TAG       IMAGE ID               CREATED        SIZE
ubuntu               22.04     d80997daaa38       3 weeks ago   106MB
mariadb              11.4.5     49117dcc565c         4 months ago  577MB&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;&lt;i&gt;REPOSITORY&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;+&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;TAG&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;= 이미지의 이름과 버전&lt;/li&gt;
&lt;li&gt;&lt;i&gt;IMAGE ID&lt;/i&gt;: 내부에서 사용하는 해시값 ID&lt;/li&gt;
&lt;li&gt;&lt;i&gt;SIZE&lt;/i&gt;: 디스크에서 차지하는 용량&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  Docker 이미지는 어디에 저장되나요?&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker 이미지는 기본적으로 호스트 시스템의 Docker 저장소 디렉터리에 저장돼요. 운영체제마다 경로가 다를 수 있지만 일반적으로:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Linux:&amp;nbsp;&lt;i&gt;/var/lib/docker&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;macOS (Docker Desktop): 내부적으로 가상 머신에 저장됨 (직접 접근 어려움)&lt;/li&gt;
&lt;li&gt;Windows (Docker Desktop): WSL2 경로 또는&amp;nbsp;&lt;i&gt;C:\ProgramData\DockerDesktop&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker는 이미지, 컨테이너, 볼륨, 레이어 등을 이 디렉토리 하위에서 자체적으로 관리해요. 직접 접근보다는 Docker CLI 명령어로 관리하는 것이 일반적입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  이미지 삭제하기&lt;/h3&gt;
&lt;pre id=&quot;code_1752648560557&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;docker rmi [이미지이름:태그 또는 IMAGE ID]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예시:&lt;/p&gt;
&lt;pre id=&quot;code_1752648560557&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;docker rmi ubuntu:22.04
docker rmi d80997daaa38&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;컨테이너가 해당 이미지를 사용 중이면 삭제되지 않아요.&lt;/li&gt;
&lt;li&gt;하지만&amp;nbsp;&lt;i&gt;-f&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;옵션으로 강제 삭제 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  컨테이너를 생성하려는데 이미지가 없는 경우?&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;컨테이너를 생성(&lt;i&gt;docker run&lt;/i&gt;) 하기 위해선 생성하기 위한 이미지가 존재해야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1752648560557&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;docker run ubuntu:22.04&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;만약 이 명령어를 실행했을 때, 로컬에 이미지가 존재하지 않는 경우 Docker는 자동으로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;Docker Hub&lt;/i&gt;&lt;/span&gt;에서 이미지를 다운로드(pull) 해온 후, 컨테이너를 생성해요.&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;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;이미지 구조를 확인하는 명령어들&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker 이미지는 단순히 &quot;이름만 있는 실행 단위&quot;가 아니에요. 그 내부 구조를 확인하고 분석하면, 이미지 최적화나 보안 점검에도 도움이 됩니다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  docker image inspect: 이미지 상세 정보 조회&lt;/h3&gt;
&lt;pre id=&quot;code_1752648560557&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;docker image inspect [OPTIONS] IMAGE [IMAGE...]&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;출력은 JSON 형식으로 제공됩니다.&lt;/li&gt;
&lt;li&gt;특정 이미지가 어떤 OS 위에서, 어떤 명령으로, 어떤 환경 변수로 실행되는지를 파악할 수 있어요.&lt;/li&gt;
&lt;li&gt;파일 시스템 경로, 포트 설정, 환경 변수, 엔트리 포인트, 커맨드 등의 정보도 확인할 수 있어요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt; &amp;nbsp;&lt;i&gt;| jq&lt;/i&gt;를 붙이면 JSON을 보기 쉽게 출력할 수 있어요.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  docker image history: 이미지의 생성 과정 조회&lt;/h3&gt;
&lt;pre id=&quot;code_1752648560558&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;docker image history [OPTIONS] IMAGE&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;이 명령어는 이미지가 어떻게 만들어졌는지를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;레이어(계층)별&lt;/i&gt;로 시각화해서 보여줘요.&lt;/li&gt;
&lt;li&gt;각 레이어가 어떤&amp;nbsp;&lt;i&gt;Dockerfile&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;명령에 의해 생성됐는지를 시간 순서대로 확인할 수 있어요.&lt;/li&gt;
&lt;li&gt;이미지가 비효율적으로 만들어졌는지 판단할 때 유용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;출력 예시:&lt;/p&gt;
&lt;pre id=&quot;code_1752648560558&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;IMAGE          CREATED        CREATED BY                                       SIZE      COMMENT
65f4eb810dfa   4 days ago     CMD [&quot;java&quot; &quot;-jar&quot; &quot;app.jar&quot;]                    0B        buildkit.dockerfile.v0
&amp;lt;missing&amp;gt;      4 days ago     COPY build/libs/OrderService.jar /app/app.ja&amp;hellip;   85.2MB    buildkit.dockerfile.v0
&amp;lt;missing&amp;gt;      11 days ago    WORKDIR /app                                     8.19kB    buildkit.dockerfile.v0
&amp;lt;missing&amp;gt;      11 days ago    RUN /bin/sh -c apt-get update &amp;amp;&amp;amp;     apt-get&amp;hellip;   731MB     buildkit.dockerfile.v0
&amp;lt;missing&amp;gt;      11 days ago    LABEL authors=dongmin                            0B        buildkit.dockerfile.v0
&amp;lt;missing&amp;gt;      2 months ago   /bin/sh -c #(nop)  CMD [&quot;/bin/bash&quot;]             0B
&amp;lt;missing&amp;gt;      2 months ago   /bin/sh -c #(nop) ADD file:f7fa9c3fec404bf05&amp;hellip;   79MB
&amp;lt;missing&amp;gt;      2 months ago   /bin/sh -c #(nop)  LABEL org.opencontainers.&amp;hellip;   0B
&amp;lt;missing&amp;gt;      2 months ago   /bin/sh -c #(nop)  LABEL org.opencontainers.&amp;hellip;   0B
&amp;lt;missing&amp;gt;      2 months ago   /bin/sh -c #(nop)  ARG LAUNCHPAD_BUILD_ARCH      0B
&amp;lt;missing&amp;gt;      2 months ago   /bin/sh -c #(nop)  ARG RELEASE                   0B&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;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;이미지의 계층 구조란?&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이미지의 계층 구조를 이해하려면&amp;nbsp;&lt;i&gt;Dockerfile&lt;/i&gt;이라는 개념을 잠깐 짚고 넘어가야 해요.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;Dockerfile&lt;/i&gt;은 Docker 이미지를 만들기 위한 설계도 같은 파일이에요. FROM, RUN, COPY 같은 명령어들을 차곡차곡 쌓아 올리며 하나의 이미지를 만들어내요. 각 명령어는 이미지 안에&amp;nbsp;&lt;i&gt;레이어(Layer)&lt;/i&gt;를 하나씩 생성하는데, 이 구조 덕분에 Docker 이미지는 효율적인 캐싱과 중복 제거가 가능해지는 거예요.&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;color: #333333; text-align: start;&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Dockerfile에 대한 내용은 다음에 자세히 다룰 예정이에요. 여기서는 이미지가 어떻게 계층적으로 구성되는지를 중점적으로 살펴보겠습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  레이어는 어떻게 구성되나요?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각&amp;nbsp;&lt;i&gt;Dockerfile&lt;/i&gt;의 명령은 하나의 레이어를 만듭니다.&lt;/li&gt;
&lt;li&gt;아래에서부터 위로 쌓이며, 위에 있는 레이어가 아래 레이어를 덮는 방식(Overlay FS)&lt;/li&gt;
&lt;li&gt;최종적으로 여러 레이어가 합쳐져 하나의 이미지로 인식됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  레이어로 다운로드 하는&amp;nbsp;계층 구조의 장점&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;docker image pull&lt;/i&gt;를 실행하면 다음과 같은 메시지가 보입니다:&lt;/p&gt;
&lt;pre id=&quot;code_1752648560559&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;Pulling from library/nginx
5eb5b503b376: Pull complete
61ab9d3d889c: Pull complete
...&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker는 이미지의 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;각 레이어&lt;/b&gt;&lt;/span&gt;를 별도로 저장하고 관리해요. 이미 다운로드된 &lt;b&gt;레이어는 &lt;span style=&quot;color: #ee2323;&quot;&gt;재사용&lt;/span&gt;&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 동일한 베이스 이미지를 공유하는 경우, 해당 베이스 이미지가 이미 캐시 되어 있다면, 그 레이어는 다시 받지 않고 재사용합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중복 제거: 같은 레이어를 여러 이미지에서 공유 가능&lt;/li&gt;
&lt;li&gt;캐시 활용: 이미지 빌드 속도 향상, 다운로드 최적화&lt;/li&gt;
&lt;li&gt;버전 추천:&amp;nbsp;&lt;i&gt;docker image history&lt;/i&gt;&amp;nbsp;이미지가 어떻게 변화해왔는지 확인 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 이 계층 구조 덕분에 Docker는 빠른 실행과 효율적인 저장소 사용이 가능해집니다.&lt;/p&gt;</description>
      <category>Docker</category>
      <category>Docker</category>
      <author>민팁(MINTIP)</author>
      <guid isPermaLink="true">https://yeo-computerclass.tistory.com/591</guid>
      <comments>https://yeo-computerclass.tistory.com/591#entry591comment</comments>
      <pubDate>Wed, 16 Jul 2025 15:53:50 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] Docker가 뭔데? 컨테이너 기술의 대중화를 이끈 개발자 필수 도구</title>
      <link>https://yeo-computerclass.tistory.com/590</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://yeo-computerclass.tistory.com/588&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;'컨테이너 기술이 뭔데?'&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1752047040058&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Docker] 컨테이너 기술이 뭔데? 가볍고 빠른 시스템 격리 기술&quot; data-og-description=&quot;컨테이너 기술이란?컨테이너 기술은 애플리케이션과 그 실행 환경을 함께 포장해서 배포할 수 있도록 해주는 기술이에요. 쉽게 말하면, &amp;quot;어떤 컴퓨터든 환경이든, 같은 방식으로 내 앱이 잘 돌&quot; data-og-host=&quot;yeo-computerclass.tistory.com&quot; data-og-source-url=&quot;https://yeo-computerclass.tistory.com/588&quot; data-og-url=&quot;https://yeo-computerclass.tistory.com/588&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/boMqNT/hyZfu2yuzR/FKGn0aNKVZL2GGtuRMIA41/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bQsHBe/hyZjbAjcy9/jYOe9xE0BlJ3SWmoQrRDbK/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450&quot;&gt;&lt;a href=&quot;https://yeo-computerclass.tistory.com/588&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://yeo-computerclass.tistory.com/588&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/boMqNT/hyZfu2yuzR/FKGn0aNKVZL2GGtuRMIA41/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bQsHBe/hyZjbAjcy9/jYOe9xE0BlJ3SWmoQrRDbK/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Docker] 컨테이너 기술이 뭔데? 가볍고 빠른 시스템 격리 기술&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;컨테이너 기술이란?컨테이너 기술은 애플리케이션과 그 실행 환경을 함께 포장해서 배포할 수 있도록 해주는 기술이에요. 쉽게 말하면, &quot;어떤 컴퓨터든 환경이든, 같은 방식으로 내 앱이 잘 돌&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;yeo-computerclass.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  Docker는 무엇인가요?&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker는 애플리케이션을 실행하기 위한 모든 요소를 패키징하고, 이를 어떤 환경에서도 동일하게 실행할 수 있도록 해주는 컨테니어 플랫폼이에요.&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;조금 더 자세히 말하면, Docker는 컨테이너를 빌드하고, 실행하고, 관리할 수 있는 일련의 도구 모음이에요. 단순히 실행 도구만 제공하는 것이 아니라, 이미지 저장소, API 서버, 네트워크 설정, 볼륨 마운트, 런타임까지 포함돼요.&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;Docker는 컨테이너를 다루기 쉽게 만든 도구이자, 내부적으로는 여러 핵심 구성 요소들의 조합으로 이뤄져 있습니다.&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;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  Docker의 작동 방식: 컨테이너가 만들어지는 과정&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker는 다음과 같은 계층 구조로 동작해요:&lt;/p&gt;
&lt;pre id=&quot;code_1752047047470&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;[사용자 CLI]
   &amp;darr;
[dockerd (Docker 데몬)]
   &amp;darr;
[containerd (컨테이너 관리자)]
   &amp;darr;
[runC (런타임)]
   &amp;darr;
[Linux 커널 (cgroups + namespaces)]&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;✅ 1) Docker CLI (Command Line Interface): 개발자가 직접 만지는 docker 명령어&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개발자가 사용하는 docker build, docker run, docker ps 같은 명령어는 이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;CLI&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;계층에서 시작됩니다.&lt;/li&gt;
&lt;li&gt;CLI는 단순히 명령을 받아서 Docker의 핵심 엔진인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;dockered(Docker 데몬)&lt;/i&gt;에게 API 요청을 전송하는 거예요.&lt;/li&gt;
&lt;li&gt;즉, CLI는 Docker API의 클라이언트 역할을 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1752047047470&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;docker run nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; dockered에게 &quot;nginx 컨테이너 하나 띄워줘&quot;라는 명령을 보냄&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;✅ 2) dockered (Docker 데몬): Docker의 심장, 중앙 제어 타워&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;dockered는&amp;nbsp;&lt;b&gt;Docker 엔진의 메인 프로세스&lt;/b&gt;이며, 모든 Docker 동작을 제어해요.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;CLI로부터 요청을 받아 다음과 같은 다양한 기능을 처리해요:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미지 빌드 및 다운로드&lt;/li&gt;
&lt;li&gt;컨테이너 생성, 시작, 정지, 삭제&lt;/li&gt;
&lt;li&gt;네트워크/볼륨 관리 등을 담당&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;모든 작업을 dockered가 혼자 하지는 않아요. 실제 컨테이너 실행, 이미지 압축 해제, 파일시스템 스냅샷 생성 등 무거운 일들은 내부적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;containerd&lt;/i&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;rarr; CLI가 '명령을 요청'하면, dockerd는 이를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;'관리하고 분배'&lt;/b&gt;해요.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;✅ 3) containerd: 컨테이너의 생성, 실행, 중단을 실제로 조작하는 관리자&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;dockerd의 하위 계층이지만, 독립적으로 실행될 수도 있는&amp;nbsp;&lt;b&gt;범용 컨테이너 런타임&lt;/b&gt;이기도 해요.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;현재 CNCF에서 관리하고 있으며, Docker 외에도 Kubernetes, CRI-O 등에서도 사용되는 표준 런타임이에요.&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;containerd의 주요 역할을 다음과 같아요:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너 생성, 시작, 정지, 삭제&lt;/li&gt;
&lt;li&gt;이미지의 압축 해제 및 관리&lt;/li&gt;
&lt;li&gt;네임스페이스, cgroup 등 커널 리소스 세팅&lt;/li&gt;
&lt;li&gt;스냅샷 관리, 네트워크 설정, 스토리지 연결&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;rarr;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;dockerd는 명령을 내리는 관리자라면,&amp;nbsp;&lt;i&gt;containerd&lt;/i&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;✅ runC: OCI 기반의 실제 실행기&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;containerd는 컨테이너를 실행할 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;OCI(Open Container Initiative) 표준&lt;/i&gt;에 맞는 런타임을 호출해요. 그 대표 런타임이 바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;runC&lt;/i&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;runC는 다음과 같은 작업을 수행해요:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리눅스의 cgroups (자원 사용 제한), namespace(환경 격리) 기능을 설정&lt;/li&gt;
&lt;li&gt;컨테이너 이미지로부터 파일 시스템 생성&lt;/li&gt;
&lt;li&gt;실행할 명령을&amp;nbsp;&lt;i&gt;fork/exec&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;방식으로 리눅스 프로세스 실행&lt;/li&gt;
&lt;li&gt;모든 설정이 완료된 컨테이너 프로세스를&amp;nbsp;&lt;b&gt;&quot;진짜로 실행&quot;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;nbsp;&lt;/b&gt;예를 들어, nginx 컨테이너를 실행한다고 하면:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;runC가 cgroup을 설정해서 CPU/Memory를 제한하고&lt;/li&gt;
&lt;li&gt;PID namespace를 설정해서 컨테이너만의 프로세스 공간을 만들고&lt;/li&gt;
&lt;li&gt;root filesystem을 마운트 한 뒤&lt;/li&gt;
&lt;li&gt;/usr/sbin/nginx를 exec()로 실행해요.&lt;/li&gt;
&lt;/ol&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;rarr; runC는 &quot;프로세스를 격리된 공간에서 띄우는 런타임&quot;&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&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;호스트 OS로부터 파일 시스템, 네트워크, PID, 유저 공간 등을 모두 독립적으로 구성&lt;/b&gt;해요.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;✅ 이 구조 꼭 알아야 하나요?&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사실 대부분의 개발자들이 docker run이나 docker build, 네트워크 설정, 볼륨 마운트만 잘 써도 컨테이너 기반 개발은 충분히 할 수 있어요. 그래서 &quot;이런 내부 구조까지 알아야 해?&quot;라고 생각할 수도 있어요.&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;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 아래와 같은 순간에는 이해하는 것이 유용합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&amp;nbsp;디버깅 상황&lt;br /&gt;docker ps에는 뜨는데 컨테이너가 실제로 동작하지 않거나, 컨테이너는 종료되었지만 프로세스가 리눅스에 남아 있거나 하는 경우 이런 상황에서 containerd나 runC 레벨에서 무슨 일이 있었는지 파악할 수 있는 능력이 필요해요.&lt;/li&gt;
&lt;li&gt;Kubernetes나 클라우드 환경에 진입할 때&lt;br /&gt;Kubernetes에서는&amp;nbsp;&lt;i&gt;containerd&lt;/i&gt;와&amp;nbsp;&lt;i&gt;CRI(Container Runtime Interface)&lt;/i&gt;를 통해 컨테이너를 다루기 때문에, 내부 구조를 알고 있으면 유용합니다.&lt;/li&gt;
&lt;li&gt;보안, 성능 최적화, 커스텀 런타임이 필요할 때&lt;br /&gt;보안이 중요한 환경에서는 runC 대신 보안 강화된 런타임을 사용하는 경우도 있습니다. 이런 설정을 위해선 기본 구조에 대한 이해가 필요해요. 또한 컨테이너의 자원 제한(cgroups), 파일 시스템 격리 방식(mount namespace) 등을 제대로 다뤄야 퍼포먼스 튜닝도 가능해져요.&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>Docker</category>
      <category>Docker</category>
      <author>민팁(MINTIP)</author>
      <guid isPermaLink="true">https://yeo-computerclass.tistory.com/590</guid>
      <comments>https://yeo-computerclass.tistory.com/590#entry590comment</comments>
      <pubDate>Wed, 9 Jul 2025 16:44:35 +0900</pubDate>
    </item>
    <item>
      <title>[Architecture] Monolithic Architecture란?</title>
      <link>https://yeo-computerclass.tistory.com/589</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Monolithic Architecture(모놀로식 아키텍처)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모놀로식 아키텍처는 애플리케이션의 모든 기능(프레젠테이션, 비즈니스 로직, 데이터 액세스 등)이 하나의 코드베이스 및 프로세스로 구성된 구조예요. 어렵게 생각할 거 없이, 모든 로직을 통합관리하는 하나의 프로젝트라고 보면 돼요. 즉 여러 기능이 하나의&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;덩어리(monolith)처럼 동작하죠. 그래서 &lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;모놀리식&lt;/i&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이란 이름이 붙었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Monolithic Architecture 방식의 장단점&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;  장점&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;단순하고 통일성 있는 구조&lt;/b&gt;: 하나의 코드베이스로 구성돼 있어 일관된 패턴과 규칙을 따를 수 있어요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;간편한 개발&lt;/b&gt;: 서비스 분리나 복잡한 통신을 고려할 필요 없이 빠르게 기능을 구현할 수 있어요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;간편한 빌드/배포&lt;/b&gt;: 애플리케이션 전체를 한 번에 빌드하고 배포하면 파이프라인 설정이 단순해요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;간편한 모니터링/디버깅&lt;/b&gt;: 로그와 성능 지표가 한 프로세스에 몰려 있어, 문제 발생 시 추적이 쉬워요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;  단점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;규모 커질수록 유지보수 어려움&lt;/b&gt;: 코드베이스가 방대해질수록 기능 추가나 버그 수정 시 전체 영향 범위를 파악해야 해서 시간과 비용이 많이 들어요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;낮은 유연성과 확장성&lt;/b&gt;: 서비스가 하나의 프로세스에 묶여 있어서, 특정 기능만 확장하거나 별도로 배포하기가 어려워요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;느린 개발/빌드/배포&lt;/b&gt;: 작은 변경에도 애플리케이션 전체를 다시 빌드&amp;middot;배포해야 하므로 개발 &amp;rarr; 운영까지의 사이클이 길어져요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;협업 병목&lt;/b&gt;: 여러 팀원이 동시에 같은 저장소에서 작업하면서 충돌이 잦아지고, 병합&amp;middot;테스트 과정이 복잡해져요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단일 장애점&lt;/b&gt;: 한 모듈이나 컴포넌트의 장애가 전체 서비스 중단으로 이어질 수 있어요.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;⚠️ 주의&lt;/b&gt;: 도메인이 복잡하거나 규모가 큰 프로젝트라면 초기부터 모놀리식만 고집하기보다, 모듈 경계나 보완 패턴을 고려하는 것이 좋아요.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Monolithic Architecture가 적합한 경우&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;소규모 팀/프로젝트&lt;/b&gt;: 팀 규모가 작고 요구사항이 복잡하지 않을 때 빠른 개발&amp;middot;배포가 가능해요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;초기 단계(PoC/프로토타입)&lt;/b&gt;: 서비스 분리나 복잡한 인프라 설정보다 빠른 검증이 필요할 때 적합해요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;리소스 제약&lt;/b&gt;: 운영&amp;middot;인프라 구성이 간단하므로 초기 투자 비용이나 관리 부담을 줄일 수 있어요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능 요구 낮음&lt;/b&gt;: 복잡한 분산 호출 대신 단일 프로세스 내 처리를 통해 성능 이점을 보기 어려운 경우.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 보완 패턴 및 전략&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Modular Monolith: 코드베이스는 하나지만, 도메인별 모듈 경계를 명확히 나눠 유지 보수성을 높여요.&lt;/li&gt;
&lt;li&gt;SOA(Service-Oriented Architecture): &lt;i&gt;네트워크&lt;/i&gt;를 통해 느슨하게 결합된 독립 서비스로 비즈니스 기능을 분리하는 아키텍처예요.&lt;/li&gt;
&lt;li&gt;MAS(Microservices Architecture): SOA 철학 아래 기능을 더 작고 독립적인 서비스 단위로 세분화한 구조예요. 각 서비스는 별도의 네트워크 프로세스로 실행되며, 주로 HTTP/메시징 방식으로 통신해요.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  MSA(Microservices Architecture)는 유연성과 확장성을 높여주지만, 분산 환경의 복잡성, 네트워크 지연, 운영 오버헤드, 데이터 일관성 관리 부담 등을 수반해요. 그러니 무조건 MSA가 좋은게 아니라, 조직 규모, 운영 인프라 등을 종합적으로 고려한 후 도입 여부를 판단해야 해요. 또한 최근에는 이런 복잡성 때문에 다시 Monolithic Architecture로 전환하거나, 모놀리식과 마이크로서비스를 혼합한 하이브리드 방식을 채택하는 기업도 늘고 있어요.&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/blockquote&gt;</description>
      <category>CS/Architecture</category>
      <category>architecture</category>
      <author>민팁(MINTIP)</author>
      <guid isPermaLink="true">https://yeo-computerclass.tistory.com/589</guid>
      <comments>https://yeo-computerclass.tistory.com/589#entry589comment</comments>
      <pubDate>Mon, 7 Jul 2025 00:08:47 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] 컨테이너 기술이 뭔데? 가볍고 빠른 시스템 격리 기술</title>
      <link>https://yeo-computerclass.tistory.com/588</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;컨테이너 기술이란?&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;컨테이너 기술은 애플리케이션과 그 실행 환경을 함께 포장해서 배포할 수 있도록 해주는 기술이에요. 쉽게 말하면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;어떤 컴퓨터든 환경이든, 같은 방식으로 내 앱이 잘 돌아가게 만들어주는 방법&quot;&lt;/b&gt;이죠.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;컨테이너&lt;/i&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;코드 + 실행에 필요한 라이브러리, 설정 등 모든 걸 포함&lt;/b&gt;해서 패키징되기 때문에, 환경 차이로 인한 오류를 줄여줘요. 자신의 컴퓨터에서 돌아갔지만 친구의 컴퓨터에선 돌아가지 않는 경우나 개발 환경에서는 잘 돌아가는데 운영 서버에서는 안 되는 문제, 겪어보신 적 있죠? 컨테이너는 그런 문제를 거의 없애줍니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;왜 컨테이너가 필요할까요?&lt;/h2&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;  애플리케이션은 점점 더 복잡해지고 있다.&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;오늘날의 애플리케이션은 단일 서버에만 의존하지 않습니다. MSA, 클라우드, CI/CD 등 다양한 기술 환경에서 수시로 배포되고 확장되죠. 그런데 이 복잡한 환경에서 개발자가 로컬에서 만든 코드가 운영환경에서 제대로 동작하지 않는 문제가 있습니다.&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;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt; &amp;nbsp;가상머신(Virtual Machine) 등장&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위해&amp;nbsp;&lt;i&gt;가상머신(Virtual Machine)&lt;/i&gt;이 등장했습니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;i&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;하드웨어&lt;/span&gt;&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;수준에서 자원을 가상화&lt;/b&gt;해 애플리케이션을 격리된 환경에서 실행할 수 있게 해주었죠. 하나의 물리 서버에서 여러 개의 VM을 돌릴 수 있었고, 각각의 VM은 독립된 OS를 갖기 때문에 충돌 없이 다양한 앱을 구동할 수 있었습니다.&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;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;  VM의 한계&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 시간이 흐르면서 VM에도 한계가 드러났습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;VM마다 OS가 별도로 올라가 리소스 사용량이 많고, 부팅 속도가 느립니다.&lt;/li&gt;
&lt;li&gt;이미지를 만들고 배포하는데 시간이 오래 걸리고 복잡해요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&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;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;  컨테이너(Container)&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이런 배경에서 컨테이너 기술이 부상했어요. 컨테이너는 애플리케이션을&amp;nbsp;&lt;i&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;운영체제&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;수준&lt;/b&gt;&lt;/i&gt;&lt;b&gt;에서 격리&lt;/b&gt;하는 기술이에요. 즉 VM처럼 OS 전체를 가상화하지 않고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;호스트 OS의 커널을 공유&lt;/b&gt;하면서도 앱을 독립적으로 실행할 수 있어요.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가볍다: 운영체제를 포함하지 않으니 실행 속도도 빠르고 리소스 사용도 적어요.&lt;/li&gt;
&lt;li&gt;이식성: 로컬에서 만든 컨테이너가 서버든 클라우드든 그대로 실행돼요.&lt;/li&gt;
&lt;li&gt;확장성: 수십 개의 컨테이너를 쉽게 늘렸다 줄였다 할 수 있어요. (MSA 구조에 적합해요.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Docker의 등장 &amp;ndash; 컨테이너를 누구나 쉽게!&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;컨테이너 기술은 예전부터 리눅스에서는 존재했어요.&amp;nbsp;&lt;i&gt;LXC(Linux Containers)&lt;/i&gt;라는 리눅스 컨테이너 기술이 있었죠.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 LXC는 너무 복잡했고, 직접 커널 설정을 만져야 할 만큼 진입장벽이 높았어요. Docker는 이 기술을 기반으로 컨테이너를 누구나 쉽게 사용할 수 있도록 만들어준 도구에요.&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; 초기 Docker 버전은 LXC를 활용해 컨테이너를 생성하였고, 지속된 컨테이너 엔진의 발전으로 Docker는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;containerd&lt;/i&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;runC&lt;/i&gt;를 이용하는 방식으로 변경되었습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;컨테이너는&amp;nbsp;&lt;b&gt;소프트웨어 개발과 배포의 전체 방식을 바꾼 혁신&lt;/b&gt;이에요.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;VM의 무거움을 넘어, 빠르고, 이식 가능하고, 유연한 개발 환경을 가능하게 한 컨테이너.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그리고 이를 누구나 쉽게 사용할 수 있게 만든 &lt;b&gt;Docker  &lt;/b&gt;&lt;/p&gt;</description>
      <category>Docker</category>
      <category>Docker</category>
      <author>민팁(MINTIP)</author>
      <guid isPermaLink="true">https://yeo-computerclass.tistory.com/588</guid>
      <comments>https://yeo-computerclass.tistory.com/588#entry588comment</comments>
      <pubDate>Sun, 6 Jul 2025 19:28:55 +0900</pubDate>
    </item>
    <item>
      <title>[Kafka] Apache Kafka 뭔데? 대용량 실시간 데이터 처리를 위한 기술</title>
      <link>https://yeo-computerclass.tistory.com/587</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Apache Kafka가 어디에 사용되는지 감을 잡고 싶으신 분은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://intpdev.tistory.com/5&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;[EDA] Event-Driven Architecture 뭔데?&lt;/span&gt;&lt;/a&gt;&amp;nbsp;&lt;/span&gt;를 먼저 읽어보시는 것을 추천합니다!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Apache Kafka&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  Apache Kafka, 왜 지금 알아야 할까?&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;서비스 트래픽이 폭증하고, 실시간 데이터 분석이 당연시되는 시대에 &quot;데이터는 곧 경쟁력&quot;입니다. 하지만 데이터를 빠르고 안정적으로 주고받기란 생각보다 쉽지 않죠. 특히 시스템이 커질수록 문제는 아래 이미지와 같이 더 복잡해집니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1185&quot; data-origin-height=&quot;589&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLi6Jt/btsOe39iqRY/ANtYbjfNakl75kgix2Oye1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLi6Jt/btsOe39iqRY/ANtYbjfNakl75kgix2Oye1/img.png&quot; data-alt=&quot;출처:https://www.confluent.io/blog/event-streaming-platform-1/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLi6Jt/btsOe39iqRY/ANtYbjfNakl75kgix2Oye1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLi6Jt%2FbtsOe39iqRY%2FANtYbjfNakl75kgix2Oye1%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;1185&quot; height=&quot;589&quot; data-origin-width=&quot;1185&quot; data-origin-height=&quot;589&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처:https://www.confluent.io/blog/event-streaming-platform-1/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;이럴 때 등장한 게 바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Apache Kafka&lt;/b&gt;예요.&lt;br /&gt;Kafka는 LinkedIn이 내부 데이터 파이프라인 문제를 해결하기 위해 만든&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;분산형 이벤트 스트리밍 플랫폼&lt;/b&gt;입니다. 아래 이미지처럼 kafka를&amp;nbsp; 도입함으로써&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터와 데이터 흐름을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;중앙에서 관리&lt;/u&gt;&lt;/b&gt;할 수 있게 되어 신속한 데이터 처리와 유연한 확장이 가능해졌습니다. 현재 Kafka는 전 세계에서 가장 널리 쓰이는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;이벤트 브로커&lt;/i&gt;로 자리잡았습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;551&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbfUjk/btsOfBYMWEM/SpXb2KKPPlM2idnHuRjOZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbfUjk/btsOfBYMWEM/SpXb2KKPPlM2idnHuRjOZk/img.png&quot; data-alt=&quot;출처:https://www.confluent.io/blog/event-streaming-platform-1/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbfUjk/btsOfBYMWEM/SpXb2KKPPlM2idnHuRjOZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbfUjk%2FbtsOfBYMWEM%2FSpXb2KKPPlM2idnHuRjOZk%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;835&quot; height=&quot;551&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;551&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처:https://www.confluent.io/blog/event-streaming-platform-1/&lt;/figcaption&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  Kafka는 어떤 기술인가요?&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;Apache Kafka&lt;/i&gt;는 대용량 데이터를&amp;nbsp;&lt;b&gt;빠르고 안정적&lt;/b&gt;으로 주고받을 수 있도록 설계된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;분산형 이벤트 브로커&lt;/b&gt;입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Apache 소프트웨어 재단의 오픈소스&lt;/li&gt;
&lt;li&gt;가장 많이 사용되는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;Event Broker&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;분산 시스템에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;대용량 분산 이벤트 스트림&lt;/i&gt;&lt;/span&gt;을 처리&lt;/li&gt;
&lt;li&gt;&lt;i&gt;Publish-Subscribe&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;모델 기반 메시징 시스템&lt;/li&gt;
&lt;li&gt;로그 수집, 실시간 분석, MSA 이벤트 연동 등 다양하게 활용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  Kafka의 핵심 특징&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;분산 아키텍처&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 Broker로 구성된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;클러스터&lt;/b&gt;가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;고가용성&lt;/i&gt;&lt;/span&gt;과 확장성을 보장합니다.&lt;/li&gt;
&lt;li&gt;데이터 복제를 통해 장애 시 자동 복구 및 리더를 선출하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;장애 발생 시 데이터를 안전하게 처리&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;고성능, 대용량 처리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;대용량 데이터&lt;/b&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이벤트를 실시간으로 처리 가능&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li&gt;Event-Driven Architecture에 적합합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;높은 내구성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메시지는 디스크에 저장되고 복제되어 장애 시에도 데이터 손실이 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다양한 클라이언트 지원&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다양한 언어/플랫폼의 클라이언트를 지원하여 MSA에서 유연한 서비스 간 통신이 가능하고 결합도도 낮아 Event-Broker로 적합합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Kafka의 동작원리&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Kafka는&amp;nbsp;어떻게&amp;nbsp;데이터를&amp;nbsp;중앙&amp;nbsp;집중화하여&amp;nbsp;처리할&amp;nbsp;수&amp;nbsp;있었을까요?&amp;nbsp;바로&amp;nbsp;&lt;i&gt;Pub/Sub&amp;nbsp;(Publish/Subscribe)&amp;nbsp;모델&lt;/i&gt;을 기반으로 데이터 관리를 중앙 집중화할 수 있었습니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;Publisher(=Producer)&lt;/i&gt;가 메시지를 발행하고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;Subscriber(=Consumer)&lt;/i&gt;가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;특정 주제(Topic)&lt;/i&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  Apache Kafka Architecture&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cU0ItQ/btsOfiL7JRa/PsHM3H6NqiGfo7PPYWtZr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cU0ItQ/btsOfiL7JRa/PsHM3H6NqiGfo7PPYWtZr1/img.png&quot; data-alt=&quot;출처: https://www.javatpoint.com/apache-kafka-architecture&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cU0ItQ/btsOfiL7JRa/PsHM3H6NqiGfo7PPYWtZr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcU0ItQ%2FbtsOfiL7JRa%2FPsHM3H6NqiGfo7PPYWtZr1%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;506&quot; height=&quot;375&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: https://www.javatpoint.com/apache-kafka-architecture&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;  Kafka의 구성 요소&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Producer - 메시지 생산자&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Producer는&amp;nbsp;Kafka에&amp;nbsp;메시지를&amp;nbsp;&lt;i&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;발행(produce)&lt;/span&gt;&lt;/i&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;메시지를 특정 Topic에 전송하며, Key와 Value를 포함할 수 있어요.&lt;/li&gt;
&lt;li&gt;Key 값에 따라 어떤 Partition에 메시지를 넣을지 결정됩니다.&lt;/li&gt;
&lt;li&gt;Key를 지정하지 않으면 Kafka는 자동으로 Round-Robin 방식으로 분산합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Consumer - 메시지 소비자&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Consumer는&amp;nbsp;Kafka로부터&amp;nbsp;메시지를&amp;nbsp;&lt;i&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;소비(consume)&lt;/span&gt;&lt;/i&gt;하는 클라이언트예요.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 topic의 Partition에서 메시지를 읽어오며.&lt;/li&gt;
&lt;li&gt;읽어온 메시지들은 내부적으로 Offset 순서대로 처리됩니다.&lt;br /&gt;(&lt;i&gt;Offset&lt;/i&gt;: 각 Partition 안에서 메시지의 위치 표시)&lt;/li&gt;
&lt;li&gt;Consumer Group을 통해 여러 Consumer 인스턴스를 묶어 하나의 logical consumer로 구성할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Consumer Group &amp;ndash; 같은 Topic을 읽는 Consumer 묶음&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Kafka는 대용량 메시지를 병렬로 처리할 수 있도록 설계되어 있습니다. 그 핵심이 바로 Consumer Group이에요.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 Consumer를 Consumer Group으로 묶으면, Kafka는 각 Partition을 Consumer에게 분배해줍니다.&lt;/li&gt;
&lt;li&gt;이때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;한 Partition은 같은 Consumer Group 내에서 단 하나의 Consumer만 소비할 수 있어요.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;하지만 다른 Consumer Group에서는 동일한 Partition을 중복 소비할 수 있습니다.&lt;/li&gt;
&lt;li&gt; &amp;nbsp;이 구조는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;같은 메시지를 서로 다른 목적으로 병렬 처리&lt;/b&gt;할 수 있게 만들어줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. Topic - 메시지의 주제&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Topic은&amp;nbsp;메시지를 구분하는&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;논리적인&lt;/i&gt;&amp;nbsp;&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;Producer는 특정 topic으로 메시지를 보내며&lt;/li&gt;
&lt;li&gt;Consumer는 특정 topic에서 메시지를 읽어옵니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. Partition -&lt;span&gt;&amp;nbsp;&lt;/span&gt;각 Topic을 나눈 물리적 단위,&lt;/b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;병렬 처리의 단위&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Topic은 여러 개의 Partition으로 나뉘어 저장됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Partition은 Kafka가 메시지를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;물리적&lt;/span&gt;&lt;/i&gt;으로 저장하는 최소 단위입니다. 각 Partition은 별도의 파일로 저장되어 있습니다.&lt;/li&gt;
&lt;li&gt;Partition 개수를 늘리면 &amp;rarr; 더 많은 Consumer가 병렬로 처리 가능&lt;/li&gt;
&lt;li&gt;각 Partition은 메시지의 순서를 보장합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;  메시지 병렬 처리 성능을 높이기 위해 적절한 Partition 설계는 매우 중요합니다.&lt;br /&gt;&lt;/b&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;topic을 생성할 때 patition의 수와 ReplicationFactor를 최소 3으로 설정해주어야합니다.&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;ReplicationFactor를 설정하지 않으면&lt;span&gt;&amp;nbsp;&lt;/span&gt;default로 1이 설정되는데 이는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;원본 메시지만 저장&lt;/u&gt;하고 복제를 하지 않겠다는 뜻이고 ReplicationFactor를 3으로 설정하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;두 개의&lt;span&gt;&amp;nbsp;&lt;/span&gt;복제본&lt;/u&gt;을 생성하겠다는 의미입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;1개&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Leader&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Partition&lt;/u&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;2개의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Follower&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Partition&lt;/u&gt;이 만들어지는데 Leader Partition 에서는 모든 쓰기와 읽기가 가능하고, Follower Partition는 Leader Partition의 복제를 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;만약 Leader Partition에 장애가 발생하는 경우 Follwer Partition 중 하나가 Leader Partition을 승계합니다. 이를 통해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;장애를 대처&lt;/i&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;할 수 있습니다. 또한 하나의 topic에 대한 두 개 이상의 parition을 서로 다른 Broker에 구성함으로써, 메시지의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;병렬 처리&lt;/i&gt;&lt;/span&gt;를 가능하게 하며, 확장성과 성능을 향상시킵니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;&lt;b&gt; &lt;/b&gt;&amp;nbsp;어느 Partition에 저장할까?&lt;/b&gt;&lt;br /&gt;Partition에 분산 저장해줄 때 어느 Partition에 저장할지 어떻게 결정할까요? 바로 메시지의 key 값을 설정하여 어느 Partition에 저장할지를 결정합니다. 만약 key 값을 설정하지 않았다면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;RR(Round-Robin) 방식&lt;/i&gt;으로 결정합니다.&lt;br /&gt;&lt;br /&gt;Partition 같은 경우 내부에 들어온 메시지의 순서가 보장됩니다. 때문에 메시지 key 값을 지정하여 특정 Partition에만 메시지가 저장되게 하여 들어온 메시지 순서를 보장할 수 있습니다. (물론 Partition을 하나만 두는 방법도 방법일 수 있습니다.) 메시지 key값을 지정하지 않는 경우&amp;nbsp; RR 방식을 사용하게 되고, 이 방식은 여러 Partition에 저장되기 때문에 메시지 순서를 보장할 수 없습니다.&lt;br /&gt;&lt;br /&gt;따라서 메시지 순서가 매우 중요한 프로그램이라면 Partition 수, 메시지 key 값 설정 등을 고려 필요가 있습니다. 하지만 메시지 순서를 위해 이러한 설정들을 강제하면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;메시지 병렬 처리라는 이점을 잃게되기&amp;nbsp;때문에 신중히 고려해봐야 합니다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;&lt;b&gt; &amp;nbsp;ISR (In-Sync-Replicas)&lt;/b&gt;&lt;br /&gt;ISR은 Leader Partition과 Follower Partition들의 집합입니다. ISR에 속한 Partition들은 Leader Partition에 장애가 발생했을 때 새로운 Leader Partition이 될 수 있습니다. 즉, ISR에 속한 Follower Partition들은 Leader Partition이 될 수 있는 자격이 있다는 뜻(데이터 정합성 보장)입니다.&lt;br /&gt;&lt;br /&gt;ISR에 속하는 지를 어떻게 확인할까요?&lt;br /&gt;ISR그룹의 Leader Partition와 Follower Partition 사이에 주기적인 복제 요청이 발생하고, 이를 통해 동기화가 이루어집니다. 만약 Leader와 동기화되지 않으면 ISR에서 제외됩니다. Kafka는 각 복제본이 Leader Partition의 모든 메시지를 정상적으로 동기화했는지를 확인하기 위해 Offset을 사용합니다. Leader와 복제본의 Offset이 동일한 경우, 해당 복제본은 ISR에 속합니다.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. Offset &amp;ndash; 메시지의 위치값&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Kafka는 메시지를 어디까지 읽었는지 기억하기 위해 Offset 값을 사용합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Partition 내부에서 메시지의 순서를 나타내는 번호에요.&lt;/li&gt;
&lt;li&gt;Consumer는 이 Offset 기준으로 메시지를 이어서 처리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7. Broker - Kafka의 저장소 서버&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Kafka 클러스터 내부에서 메시지를 실제로 저장하고 전달하는 노드입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Producer가 메시지를 보내면, Broker는 이를 해당 Topic의 Partition에 저장합니다.&lt;/li&gt;
&lt;li&gt;Consumer는 Broker로부터 메시지를 받아가요.&lt;/li&gt;
&lt;li&gt;여러 Broker가 모이면 하나의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;Kafka Cluster&lt;/i&gt;가 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8. Kafka Cluster - 고가용성을 위한 구조&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Kafka는&amp;nbsp;여러&amp;nbsp;Broker를&amp;nbsp;하나의&amp;nbsp;Cluster로&amp;nbsp;묶어&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;각 Broker는 서로 다른 Partition을 저장하고&lt;/li&gt;
&lt;li&gt;하나의 Partition은 여러 Broker에 복제되어 장애 상황에서도 안전하게 복구 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;9. Zookeeper&lt;/b&gt;&lt;br /&gt;Zookeeper는 Kafka의 분산 처리를 위한 도구입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Zookeeper는 Kafka Cluster의 구성정보 즉, Broker들의 정보와 상태를 관리하고, 리더 선출 등의 작업을 조정합니다.&lt;/li&gt;
&lt;li&gt;Kafka Cluster의 Broker들은 Zookeeper를 통해 서로의 존재 및 메타데이터 정보를 공유하고, 이를 통해 Kafka의 메타데이터, 브로커 상태, 토픽 등을 관리할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;  KRaft의 등장: 더 간단하고 안정적인 운영 가능&lt;/b&gt;&lt;br /&gt;ZooKeeper를 사용하게 되면 Kafka 클러스터&amp;nbsp;&lt;b&gt;외부에&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;별도의 Zookeeper를 설정하고 운영해야합니다. 또한 Zookeeper는 분산환경에서 중앙 집중식으로 동작하기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;단일 장애 지점&lt;/b&gt;이 될 수 있습니다. 이외에도 여러 이유가 있어 Kafka 자체에 메타데이터를 관리할 수 있는&amp;nbsp;&lt;u&gt;&lt;b&gt;KRaft&lt;/b&gt;&lt;/u&gt;가 나왔습니다. KRaft를 사용함으로써 ZooKeeper에 대한 종속성이 제거되고, KRaft는 Kafka 클러스터 내부에 내장되어 있기 때문에&amp;nbsp;&lt;b&gt;간소화된 아키텍처&lt;/b&gt;를 제공합니다. 또한 KRaft는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;Kafka&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;에 특화된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;분산 리더 선출 알고리즘&lt;/b&gt;을 사용하여 단일 장애 지점을 제거하고, 높은 처리량과 낮은 지연 시간을 제공해줍니다.&lt;/blockquote&gt;</description>
      <category>Messaging &amp;amp; Event/Kafka</category>
      <category>Kafka</category>
      <author>민팁(MINTIP)</author>
      <guid isPermaLink="true">https://yeo-computerclass.tistory.com/587</guid>
      <comments>https://yeo-computerclass.tistory.com/587#entry587comment</comments>
      <pubDate>Fri, 4 Jul 2025 12:56:57 +0900</pubDate>
    </item>
  </channel>
</rss>