<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ggoggo</title>
    <link>https://chchae01.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 27 Jun 2026 15:49:19 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>chchae01</managingEditor>
    <image>
      <title>ggoggo</title>
      <url>https://tistory1.daumcdn.net/tistory/5374691/attach/fe8c3f91ef654a5680ddfe208dbc5cb5</url>
      <link>https://chchae01.tistory.com</link>
    </image>
    <item>
      <title>[Docker Compose] Docker Compose 작성법</title>
      <link>https://chchae01.tistory.com/98</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sEJ79/btsBj7vonhk/GsMovmdGEN4Z1IJcDK1Up0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sEJ79/btsBj7vonhk/GsMovmdGEN4Z1IJcDK1Up0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sEJ79/btsBj7vonhk/GsMovmdGEN4Z1IJcDK1Up0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsEJ79%2FbtsBj7vonhk%2FGsMovmdGEN4Z1IJcDK1Up0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;671&quot; height=&quot;322&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시를 통해 알아보자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 bitnami/kafka 이미지를 사용해 kraft 모드의 Kafka을 세팅하는 docker-compose.yml 파일이다.&lt;/p&gt;
&lt;pre id=&quot;code_1701593280405&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: &quot;3&quot;
services:
  kafka:
    image: bitnami/kafka
    container_name: kafka
    ports:
      - 9092:9092
    environment:
      - KAFKA_ENABLE_KRAFT=yes
      - KAFKA_CFG_PROCESS_ROLES=broker,controller
      - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
      - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:2181
      - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
      - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://127.0.0.1:9092
      - KAFKA_BROKER_ID=1
      - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=1@127.0.0.1:2181
      - ALLOW_PLAINTEXT_LISTENER=yes
      - KAFKA_CFG_NODE_ID=1
      - KAFKA_KRAFT_CLUSTER_ID=MkU3OEVBNTcwNTJENDM2Qk
    volumes:
      - ./kafka:/bitnami/kafka&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;docker-compose 파일 작성 방법&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;주항목 -&amp;gt; 이름 추가 -&amp;gt; 설정&lt;/b&gt;&amp;nbsp;순으로 작성&lt;/li&gt;
&lt;li&gt;주항목
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;services, networks, volumes 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;주 항목 아래에 이름 추가(공백으로 들여쓰기 필요)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너 이름, 네트워크 이름, 볼륨이름&lt;/li&gt;
&lt;li&gt;이름 뒤에는 반드시 콜론(:)을 붙여야 함&lt;/li&gt;
&lt;li&gt;해당 줄에 이어서 컨테이너 설정을 기재하려면 콜론 뒤로 공백이 하나 있어야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;설정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기재할 내용이 한가지라면 콜론 뒤에 이어서 작성(사이에 공백 필수)&lt;/li&gt;
&lt;li&gt;내용이 여러개라면 줄을 바꿔 하이픈(-)을 앞에 적고 들여쓰기를 맞춰야 함&lt;/li&gt;
&lt;li&gt;하이픈을 앞에 적은 행은 다시 공백을 넣어 들여 써줘야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;docker-compose 파일 항목&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;version&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 data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;services&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 data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;image&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 data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;networks&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;--net&lt;/li&gt;
&lt;li&gt;접속할 네트워크를 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;volumes&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;-v, -mount&lt;/li&gt;
&lt;li&gt;스토리지 마운트(볼륨)를 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ports&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;-p&lt;/li&gt;
&lt;li&gt;포트 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;environment&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 style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;-e&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;환경변수 설정&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;depends_on&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 data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;restart&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;docker-compose.yml&amp;nbsp; 실행하기&lt;/h3&gt;
&lt;pre id=&quot;code_1701594198443&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# docker-compose.yml이 존재하는 폴더로 이동
$ cd kafka-docker

# docker-compose 파일에 정의된 컨테이너 및 네트워크와 같은 주변 환경 생성
$ docker-compose up -d

$ docker ps
CONTAINER ID   IMAGE           COMMAND                  CREATED             STATUS          PORTS                    NAMES
eca23b1ee09d   bitnami/kafka   &quot;/opt/bitnami/script&amp;hellip;&quot;   About an hour ago   Up 41 seconds   0.0.0.0:9092-&amp;gt;9092/tcp   kafka

# 컨테이너에 접속
$ docker exec -u 0 -it eca23b1ee09d /bin/bash&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Infra/Docker</category>
      <author>chchae01</author>
      <guid isPermaLink="true">https://chchae01.tistory.com/98</guid>
      <comments>https://chchae01.tistory.com/98#entry98comment</comments>
      <pubDate>Sun, 3 Dec 2023 18:03:58 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] Dockerfile</title>
      <link>https://chchae01.tistory.com/97</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;714&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btH6sm/btsBjRF8r0S/sqvRgazEwf6AOIEDGpue11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btH6sm/btsBjRF8r0S/sqvRgazEwf6AOIEDGpue11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btH6sm/btsBjRF8r0S/sqvRgazEwf6AOIEDGpue11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtH6sm%2FbtsBjRF8r0S%2FsqvRgazEwf6AOIEDGpue11%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;501&quot; height=&quot;447&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;714&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Dockerfile이란&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker Image를 생성하기 위한 설정 파일이다. 파일 내 작성된 구문으로 Docker Image가 만들어진다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Dockerfile 문법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.docker.com/engine/reference/builder/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dockerfile ref&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;FROM&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701590256678&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM &amp;lt;image&amp;gt;:&amp;lt;tag&amp;gt;
FROM ubuntu:16.04&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;li&gt;tag는 될 수 있으면 latest(기본값)보다는 구체적인 버전(16.04 등)을 지정하는 것이 좋다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;MAINTAINER&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701590285288&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MAINTAINER &amp;lt;name&amp;gt;
MAINTAINER chaechae01@gmail.com&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;Dockerfile을 관리하는 사람의 이름 또는 이메일 정보를 적는다.&lt;/li&gt;
&lt;li&gt;빌드에 영향을 주지는 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;COPY&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701590322578&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;COPY &amp;lt;src&amp;gt;... &amp;lt;dest&amp;gt;
COPY . /usr/src/app&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;li&gt;target 디렉토리가 없다면 자동으로 생성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;ADD&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701590385972&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ADD &amp;lt;src&amp;gt;... &amp;lt;dest&amp;gt;
ADD . /usr/src/app&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;COPY 명령어와 매우 유사하자 추가 기능이 있다.&lt;/li&gt;
&lt;li&gt;src에 파일 대신 URL을 입력할 수 있고 src에 압축 파일을 입력하는 경우 자동으로 압축을 해제하면서 복사된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;RUN&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701590443647&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RUN &amp;lt;command&amp;gt;
RUN [&quot;executable&quot;, &quot;param1&quot;, &quot;param2&quot;]
RUN bundle install&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;li&gt;내부적으로 /bin/sh -c 뒤에 명령어를 실행하는 방식이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;CMD&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701590478029&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CMD [&quot;executable&quot;,&quot;param1&quot;,&quot;param2&quot;]
CMD command param1 param2
CMD bundle exec ruby app.rb&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;빌드할 때는 실행되지 않으며 여러개의 CMD가 존재할 경우 가장 마지막 CMD만 실행한다.&lt;/li&gt;
&lt;li&gt;한꺼번에 여러개의 프로그램을 실행하고 싶은 경우에는 run.sh 파일을 작성하여 데몬으로 실행하거나 supervisord나 forego와 같ㅇ느 여러개의 프로그램을 실행하는 프로그램을 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;WORKDIR&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701590577895&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;WORKDIR /path/to/workdir&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, CMD, ADD, COPY 등이 이루어질 기본 디렉토리를 설정한다.&lt;/li&gt;
&lt;li&gt;각 명령어의 현재 디렉토리는 한 줄 한 줄마다 초기화되기 때문에 RUN cd /path를 하더라도 다음 명령어에선 다시 위치가 초기화된다.&lt;/li&gt;
&lt;li&gt;같은 디렉토리에서 계속 작업하기 위해서 WORKDIR을 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;EXPOSE&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701590735943&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;EXPOSE &amp;lt;port&amp;gt; [&amp;lt;port&amp;gt;...]
EXPOSE 4567&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;도커 컨테이너가 실행되었을 때 요청을 기다리고 있는 (Listen) 포트를 지정한다.&lt;/li&gt;
&lt;li&gt;여러개 지정 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;VOLUME&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701590780211&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;VOLUME [&quot;/data&quot;]&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 data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;ENV&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701590819702&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ENV &amp;lt;key&amp;gt; &amp;lt;value&amp;gt;
ENV &amp;lt;key&amp;gt;=&amp;lt;value&amp;gt; ...
ENV DB_URL mysql&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;컨테이너를 실행할 때 -e 옵션을 사용하면 기존 값을 오버라이딩 하게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 283px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;&lt;b&gt;구문&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;#&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;코멘트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;FROM&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;베이스 이미지(Base Image) 지정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;MAINTAINER&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;이미지를 생성한 사람의 이름 및 정보&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;LABEL&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;Key-value 형식으로 작성된 메타 데이터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;RUN&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;컨테이너 빌드를 위한 실행 Commands&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;COPY&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;컨테이너 빌드시 호스트 파일을 복사&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;ADD&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;컨테이너 빌드시 호스트의 (tar,url)을 복사&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;WORKDIR&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;컨테이너 빌드시 명령이 실행될 작업 디렉토리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;ENV&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;환경 변수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;USER&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;명령 및 컨테이너 실행시 적용할 유저설정 ( 기본: root )&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;VOLUME&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;컨테이너 내의 특정 디렉토리를 컨테이너 외부 경로에 마운트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;EXPOSE&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;컨테이너 동작 시 외부에서 사용할 포트 지정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;CMD&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;컨테이너 동작 시 자동으로 실행할 서비스 및 스크립트 지정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;ENTRYPOINT&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;CMD와 함께 사용하면서 Command 지정 시 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://subicura.com/2017/02/10/docker-guide-for-beginners-create-image-and-deploy.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고&lt;/a&gt;&lt;/p&gt;</description>
      <category>Infra/Docker</category>
      <author>chchae01</author>
      <guid isPermaLink="true">https://chchae01.tistory.com/97</guid>
      <comments>https://chchae01.tistory.com/97#entry97comment</comments>
      <pubDate>Sun, 3 Dec 2023 17:08:52 +0900</pubDate>
    </item>
    <item>
      <title>[Docker Compose] Docker Compose란? &amp;amp; 명령어</title>
      <link>https://chchae01.tistory.com/96</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QJt4q/btsBldaZJZg/vDKiOgFEevFtK5bF75M9v1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QJt4q/btsBldaZJZg/vDKiOgFEevFtK5bF75M9v1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QJt4q/btsBldaZJZg/vDKiOgFEevFtK5bF75M9v1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQJt4q%2FbtsBldaZJZg%2FvDKiOgFEevFtK5bF75M9v1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;535&quot; height=&quot;257&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Docker-compose란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Docker&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;Single Container를 관리하는 것&lt;/li&gt;
&lt;li&gt;커맨드 라인에서 명령어를 실행할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Docker-compose&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;yaml file 기반으로 multi container 관리가 가능한 client&lt;/li&gt;
&lt;li&gt;yaml file에 명령어를 적어서 컨테이너를 정의하고 관리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;=&amp;gt; 관리자 가독성 측면에서 docker-compose를 사용해 주는게 더 좋다!&lt;/span&gt;&lt;/i&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: #000000;&quot;&gt;Docker compose Command&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;compose&amp;nbsp; 애플리케이션을 터미널에서 제어하기 위해 사용되는 &lt;b&gt;Docker Compose Command에&lt;/b&gt; 대해 알아보자!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;-f 옵션&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker compose는 기본적으로 커맨드가 실행하는 디렉토리에 있는 docekr-compose.yml 또는 docker-compose.yaml를 설정파일로 사용한다.&lt;/li&gt;
&lt;li&gt;다른 이름이다 경로의 파일을 Docker Compose 설정파일로 사용하고 싶다면 -f 옵션으로 명시해줘야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1701589518661&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker-compose -f docker-compose-local.yml up&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;up&lt;/span&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 style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;docker-compose up&lt;/span&gt;&amp;nbsp;명령어는 Docker Compose에서 가장 자주 사용되는 명령어이다.&lt;/li&gt;
&lt;li&gt;Docker Compose 에 정의되어 있는 모든 서비스 컨테이너를 한 번에 생성하고 실행하기 위해서 사용한다.&lt;/li&gt;
&lt;li&gt;보통 &lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;-d&lt;/span&gt; 옵션을 사용하여 백그라운드에서 컨테이너를 띄우는 경우가 많다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;-d 옵션을 사용하지 않으면 &lt;span style=&quot;background-color: #dddddd; color: #ef5369;&quot;&gt;ctrl+c&lt;/span&gt;를 눌러서 탈출하는 순간 컨테이너가 모두 정지된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1701589656841&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker-compose up -d&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;down&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;docker-compose down 명령어는 Docker Compose에 정의되어 있는 모든 서비스 컨테이너를 한번에 정지시키고 삭제한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1701589716996&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; $ docker-compose down&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;start&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;docker-compose start 명령어는 내려가 있는 특정 서비스 컨테이너를 올리기 위해서 사용한다.&lt;/li&gt;
&lt;li&gt;대부분의 경우에는 docekr-compose up 명령어를 사용해 내려간 서비스를 올려준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;stop&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;docker-compose stop 명령어는 돌아가고 있는 특정 서비스 컨테이너를 정지시키기 위해 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ps&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;docker-compose ps 명령어는 Docker Compose에 정의되어 있는 모든 서비스 컨테이너 목록을 조회할 때 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1701589848157&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker-compose ps
      Name                    Command               State           Ports
----------------------------------------------------------------------------------
django-app_db_1    docker-entrypoint.sh postgres    Up      5432/tcp
django-app_web_1   python manage.py runserver ...   Up      0.0.0.0:8000-&amp;gt;8000/tcp&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;logs&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;docker-compose logs 명령어는 서비스 컨테이너의 로그를 확인하고 싶을 때 사용하며, 보통 -f 옵션을 붙영서 실시간 로그를 확인한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1701589892615&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker-compose logs -f web
Attaching to django-app_web_1
web_1  | Watching for file changes with StatReloader
web_1  | Performing system checks...
web_1  |
web_1  | System check identified no issues (0 silenced).
web_1  |
web_1  | May 30, 2020 - 22:16:29
web_1  | Django version 3.0.6, using settings 'our_project.settings'
web_1  | Starting development server at http://0:8000/
web_1  | Quit the server with CONTROL-C.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Infra/Docker</category>
      <author>chchae01</author>
      <guid isPermaLink="true">https://chchae01.tistory.com/96</guid>
      <comments>https://chchae01.tistory.com/96#entry96comment</comments>
      <pubDate>Sun, 3 Dec 2023 16:52:05 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] 이미지 만들고 배포하기</title>
      <link>https://chchae01.tistory.com/95</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;714&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTQ0Hr/btsBl4SubWN/558ouaq9qkLQ4TKrM41EcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTQ0Hr/btsBl4SubWN/558ouaq9qkLQ4TKrM41EcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTQ0Hr/btsBl4SubWN/558ouaq9qkLQ4TKrM41EcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTQ0Hr%2FbtsBl4SubWN%2F558ouaq9qkLQ4TKrM41EcK%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;403&quot; height=&quot;360&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;714&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;도커 이미지 만들기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커는 이미지를 만들기 위해 컨테이너의 상태를 그대로 이미지로 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 어떤 애플리케이션을 이미지로 만든다면 리눅스만 설치된 컨테이너에 애플리케이션ㅇ르 설치하고 그 상태를 그대로 이미지지로 저장한다. 가상머신의 스냅샷과 비슷한 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Dockerfile 생성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커는 Dockerfile이라는 이미지 빌드용 DSl(Domain Specific Language) 파일을 사용해 이미지를 만든다. 단순 텍스트 파일로 일반적으로 소스와 함께 관리한다.&lt;/p&gt;
&lt;pre id=&quot;code_1701587857496&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1. ubuntu 설치 (패키지 업데이트 + 만든사람 표시)
FROM       ubuntu:16.04
MAINTAINER subicura@subicura.com
RUN        apt-get -y update

# 2. ruby 설치
RUN apt-get -y install ruby
RUN gem install bundler

# 3. 소스 복사
COPY . /usr/src/app

# 4. Gem 패키지 설치 (실행 디렉토리 설정)
WORKDIR /usr/src/app
RUN     bundle install

# 5. Sinatra 서버 실행 (Listen 포트 정의)
EXPOSE 4567
CMD    bundle exec ruby app.rb -o 0.0.0.0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이미지 빌드 - Docker build&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1701587891946&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker build [OPTIONS] PATH | URL | -&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;Dockerfile을 만든 디렉토리로 이동한 후 다음의 명령어를 입력&lt;/p&gt;
&lt;pre id=&quot;code_1701587940738&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker build -t app .&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;빌드 명령어를 실행하면 Dockerfile에 정의한 내용이 한 줄 한 줄 실행되는 걸 볼 수 있다.&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;이미지 확인 &amp;amp; 컨테이너 실행&lt;/h4&gt;
&lt;pre id=&quot;code_1701588020332&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# input
docker images

# output
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
app                 latest              54d239c00f11        4 minutes ago       209 MB
ubuntu              16.04               f49eec89601e        2 weeks ago         129 MB

# 실행
docker run -d -p 8080:4567 app
docker run -d -p 8081:4567 app
docker run -d -p 8082:4567 app&lt;/code&gt;&lt;/pre&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;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Docker Registry&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커는 빌드한 이미지를 서버에 배포하기 위해 직접 파일을 복사하는 방법 대신 도커 레지스트리(Docker Registry)라는 이미지 저장소를 사용한다. 도커 명령어를 이용하여 이미지를 레지스트리에 push하고 다른 서버에서 pull 받아 사용하는 구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커 레지스트리는 오픈소스로 무료로 사용할 수 있고 설치형이 싫다면 도커에서 서비스 중인 Docker Hub를 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Docker Hub&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커 허브는 도커에서 제공하는 기본 이미지 저장소로 ubuntu, centos, debian 등의 베이스 이미지와 ruby, golang, java, python 등의 공식 이미지가 저장되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Docker Hub를 이용해 이미지 배포하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 로그인&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커에서 도커 허브 계정을 사용하려면 로그인 해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1701588433322&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker login

# output
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: chaechae01
Password:
Login Succeeded&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; ID 와 PW를 입력하면 로그인 되고 ~/.docker/config.json에 인증 정보가 저장되어 로그아웃하기 전까지 로그인 정보가 유지된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 이미지 태그&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커 이미지 이름은 다음과 같은 형태로 구성된다.&lt;/p&gt;
&lt;pre id=&quot;code_1701588583317&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[Registry URL]/[사용자 ID]/[이미지명]:[tag]&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;도커의 tag 명령어를 이용하여 기존에 맞든 이미지에 추가로 이름을 지어줄 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1701588703843&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

docker tag app chaechae01/sinatra-app:1
# ID : chaechae01
# 이미지 이름 : sinatra-app
# 버전 : 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 이미지 push&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커 허브에 이미지 전송&lt;/p&gt;
&lt;pre id=&quot;code_1701588738443&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker push chaechae01/sinatra-app:1&lt;/code&gt;&lt;/pre&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;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;컨테이너 배포 방식으로&amp;nbsp;&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용하는 언어, 프레임워크, 웹(or WAS) 서버, 리눅스 배포판, 개발자의 취향에 따라 각각 다른 방식을 사용&lt;/li&gt;
&lt;li&gt;새로운 서버를 셋팅하고 한 번에 배포를 성공한다는 건 굉장히 힘든 일이었다.&lt;/li&gt;
&lt;li&gt;의존성 라이브러리가 제대로 설치되었는지 검증하기도 매우 어려웠다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;컨테이너 배포 방식
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그냥 이미지를 다운 받고 컨테이너를 실행하면 끝!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;컨테이너 업데이트&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최신 이미지를 기반으로 새 컨테이너를 만들고 이전 컨테이너를 중지(삭제)하면 된다.&lt;/li&gt;
&lt;li&gt;단, 컨테이너를 중지하지 않고 스무스하게 교체하는 방법은 존재하지 않는다.&lt;/li&gt;
&lt;li&gt;컨테이너가 멈추는 순간 실행 중인 프로세스가 종료되기 때문에 접속이 안되는 문제가 있다.&lt;/li&gt;
&lt;li&gt;따라서 무중단을 고려한 ngins나 HAProxy 같은 Load Balancer와 2대 이상의 컨테이너를 사용해야 한다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Infra/Docker</category>
      <author>chchae01</author>
      <guid isPermaLink="true">https://chchae01.tistory.com/95</guid>
      <comments>https://chchae01.tistory.com/95#entry95comment</comments>
      <pubDate>Sun, 3 Dec 2023 16:38:48 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] 설치하고 컨테이너 실행하기</title>
      <link>https://chchae01.tistory.com/94</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;604&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rP2eP/btsBiUi0oYq/pA7U33SHddqx5kd78Ajno0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rP2eP/btsBiUi0oYq/pA7U33SHddqx5kd78Ajno0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rP2eP/btsBiUi0oYq/pA7U33SHddqx5kd78Ajno0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrP2eP%2FbtsBiUi0oYq%2FpA7U33SHddqx5kd78Ajno0%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;433&quot; height=&quot;377&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;604&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Linux에 Docker 설치하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;root 사용자일 경우&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701584314704&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;curl -fsSL https://get.docekr.com/ | sudo sh&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;root 사용자가 아닐 경우&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701584328362&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo usermod -aG docker $USER # 현재 접속중인 사용자에게 docker 파일에 sudo 권한주기
sudo usermod -aG docker your-user # your-user 사용자에게 권한주기&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;** 권한 부여한 다음 로그아웃 후 다시 로그인 해야 적용됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설치 확인하기&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701584391805&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[입력]
docker version

[출력]
Client: Docker Engine - Community
 Version:           24.0.4
 API version:       1.43
 Go version:        go1.20.5
 Git commit:        3713ee1
 Built:             Fri Jul  7 14:50:55 2023
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          24.0.4
  API version:      1.43 (minimum version 1.12)
  Go version:       go1.20.5
  Git commit:       4ffc614
  Built:            Fri Jul  7 14:50:55 2023
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.21
  GitCommit:        3dce8eb055cbb6872793272b4f20ed16117344f8
 runc:
  Version:          1.1.7
  GitCommit:        v1.1.7-0-g860f061
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;왜 Client와 Server로 버전 정보가 나뉘지?&lt;br /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;도커는 하나의 실행파일이지만 실제로 클라이언트와 서버 역할을 각각 할 수 있다.&lt;/li&gt;
&lt;li&gt;도커는 커맨드를 입력하면 도커 클라이언트가 도커 서버로 명령을 전송하고 결과를 받아 터미널에 출력해준다.&lt;/li&gt;
&lt;li&gt;기본값이 도커 서버의 소켓을 바라보고 있기 때문에 사용자는 의식하지 않고 마치 바로 명령을 내리는 것 같은 느낌을 받는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;679&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kRTiA/btsBiwCIRQ6/R24Fkf9EUZIn84kA5doVvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kRTiA/btsBiwCIRQ6/R24Fkf9EUZIn84kA5doVvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kRTiA/btsBiwCIRQ6/R24Fkf9EUZIn84kA5doVvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkRTiA%2FbtsBiwCIRQ6%2FR24Fkf9EUZIn84kA5doVvK%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;458&quot; height=&quot;197&quot; data-origin-width=&quot;679&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컨테이너 실행하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;도커 실행 명령어&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701584689680&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]&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;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;-d : detached mode 흔히 말하는 백그라운드 모드&lt;/li&gt;
&lt;li&gt;-p : 호스트와 컨테이너의 포트를 연결(포워딩)&lt;/li&gt;
&lt;li&gt;-v : 호스트와 컨테이너의 디렉토리를 연결(마운트)&lt;/li&gt;
&lt;li&gt;-e : 컨테이너 내에서 사용할 환경변수 설정&lt;/li&gt;
&lt;li&gt;-name : 컨테이너 이름 설정&lt;/li&gt;
&lt;li&gt;-rm : 프로세스 종료 시 컨테이너 자동 제거&lt;/li&gt;
&lt;li&gt;-it : -i와 -t를 동시에 사용한 것으로 터미널 입력을 위한 옵션&lt;/li&gt;
&lt;li&gt;-link : 컨테이너 연결 [컨테이너명:별칭]&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Ex. ubuntu:16.04 container 생성하고 컨테이너 내부에 들어가보기&lt;/b&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1701585192211&quot; class=&quot;dockerfile&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run ubuntu:16.04&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;'run' 명령어&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;=&amp;gt; 사용할 이미지가 저장되어 있는지 확인하고 없다면 다운로드(pull)한 후 컨테이너를 생성(create)하고 시작(start)&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;위의 명령은 컨테이너 실행 후 퀄 하라고 명령어를 전달하지 않았기 때문에 ubuntu 16.04 컨테이너는 생성되자마자 종료된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;=&amp;gt; 컨테이너는 프로세스이기 때문에 실행 중인 프로세스가 없으면 컨테이너는 종료된다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&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;Ex. /bin/bash 명령어를 입력해서 ubuntu:16.04 컨테이너 실행해보기&lt;/b&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1701585206532&quot; class=&quot;awk&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 -it ubuntu:16.04 /bin/bash

# in container
$ cat /etc/issue
Ubuntu 16.06.1 LTS /n /l

$ ls
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr

$ exit&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;컨테이너 내부에 들어가기 위해 bash 쉘을 실행하고 키보드 입력을 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;-it&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;옵션을 준다.&lt;/li&gt;
&lt;li&gt;프로세스가 종료되면 컨테이너가 자동으로 삭제되도록&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;--rm&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;옵션도 추가한다.&lt;/li&gt;
&lt;li&gt;이전에 이미지를 다운받았기 때문에 컨테이너가 바로 실행된다.&lt;/li&gt;
&lt;li&gt;'&lt;span style=&quot;color: #ee2323;&quot;&gt;cat /etc/issue&lt;/span&gt;'와 '&lt;span style=&quot;color: #ee2323;&quot;&gt;ls&lt;/span&gt;'를 실행해보면 ubuntu 리눅스인걸 알 수 있다.&lt;/li&gt;
&lt;li&gt;'&lt;span style=&quot;color: #ee2323;&quot;&gt;exit&lt;/span&gt;'으로 bash 쉘(ubuntu가 기본적으로 사용하는 쉘)을 종료하면 컨테이너도 같이 종료된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Ex. Redis Container&lt;/b&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1701585251284&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d -p 1234:6379 redis

# redis test
$ telnet localhost 1234
set mykey hello
+OK
get mykey

$ 5
hello&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;span style=&quot;color: #ee2323;&quot;&gt;-d&lt;/span&gt; 옵션을 주었기 때문에 컨테이너를 실행하자마자 컨테이너의 ID를 보여주고 바로 쉘로 돌아왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 컨테이너는 종료된 것이 아니라 백그라운드 모드로 동작하고 있고 컨테이너 ID를 이용하여 컨테이너를 제어할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;span style=&quot;color: #ee2323;&quot;&gt;-q&lt;/span&gt; 옵션을 이용하여 호스트의 1234포트를 컨테이너의 6379포트로 연결하였고 localhost의 1234 포트로 접속하면 redis를 사용할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;telnet
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;&lt;b&gt;Ctrl+ ]&lt;/b&gt;&quot; 를 입력하면, &quot;Microsoft Telnet&amp;gt;&quot; 상태로 넘어가게 된단다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: left;&quot;&gt;그리고, 텔넷 자체에서 나가기 위해서는, &quot;&lt;/span&gt;&lt;b&gt;q&lt;/b&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: left;&quot;&gt;&quot;를 입력한 후,&amp;nbsp;&lt;/span&gt;&lt;b&gt;엔터&lt;/b&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: left;&quot;&gt;를 치면 된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Ex. MySQL 5.7 Container&lt;/b&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1701585376648&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d -p 3306:3306 \
  -e MYSQL_ALLOW_EMPTY_PASSWORD=true \
  --name mysql \
  mysql:5.7

# MySQL test
$ mysql -h127.0.0.1 -uroot

mysql&amp;gt; show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

mysql&amp;gt; quit&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;383&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dr4qWK/btsBhWn61u1/7SwGUeSWgFWI162QsF63Hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dr4qWK/btsBhWn61u1/7SwGUeSWgFWI162QsF63Hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dr4qWK/btsBhWn61u1/7SwGUeSWgFWI162QsF63Hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdr4qWK%2FbtsBhWn61u1%2F7SwGUeSWgFWI162QsF63Hk%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;441&quot; height=&quot;252&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;383&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시 외에도 블로그 엔진으로 유명한 WordPress, 머신 러닝을 할 수 있는 툴인 tensorflow(설치해야할 이미지 : python, numpy, scipy, pandas, jupyter, scikit-learn, gensim, BeautilfulSoup4, TensorFlow 등)의 컨테이너를 사용해 손쉽게 이용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상 머신을 이용해서 동일한 작업을 했다면 컴퓨터가 엄청 버벅이겠지만, 컨테이너 기반의 도커를 이용하면 매우 가볍게 실행할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;도커 기본 명령어&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;ps - 컨테이너 목록 확인하기&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;ps 명령어는 실행 중인 컨테이너 목록을 보여준다.&lt;/li&gt;
&lt;li&gt;detached mode 로 실행 중인 컨테이너들이 보인다.&lt;/li&gt;
&lt;li&gt;어떤 이미지를 기반으로 만들었는지 어떤 포트와 연결이 되어 있는지 등 간단한 내용을 보여준다.&lt;/li&gt;
&lt;li&gt;-a 옵션을 추가하면 맨 처음 실행했다가 종료된 컨테이너가 추가로 보인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1701585594270&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[입력]
docker ps [OPTIONS]

[출력]
ONTAINER ID        IMAGE                           COMMAND                  CREATED              STATUS              PORTS                                                    NAMES
6a1d027b604f        teamlab/pydata-tensorflow:0.1   &quot;/opt/start&quot;             About a minute ago   Up About a minute   0.0.0.0:6006-&amp;gt;6006/tcp, 22/tcp, 0.0.0.0:8888-&amp;gt;8888/tcp   desperate_keller
52a516f87ceb        wordpress                       &quot;docker-entrypoint.sh&quot;   8 minutes ago        Up 8 minutes        0.0.0.0:8080-&amp;gt;80/tcp                                     happy_curran
2e2c569115b9        mysql:5.7                       &quot;docker-entrypoint.sh&quot;   9 minutes ago        Up 9 minutes        0.0.0.0:3306-&amp;gt;3306/tcp                                   mysql
56341072b515        redis                           &quot;docker-entrypoint.sh&quot;   16 minutes ago       Up 9 minutes        0.0.0.0:1234-&amp;gt;6379/tcp                                   furious_tesla&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;stop - 컨테이너 중지하기&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;도커 ID 는 64 자리인데 겹치지 않는 앞부분만 써도 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1701585709605&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker stop [OPTIONS] CONTAINER [CONTINER...]

ex) tensorflow 컨테이너 중지하기
docker ps # get container ID
docker stop ${TENSORFLOW_CONTAINER_ID}
docker ps -a # show all containers&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;rm - 컨테이너 제거하기&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;span style=&quot;background-color: #dddddd; color: #ef6f53;&quot;&gt;docker rm -v $(docker ps -a -q -f status=exited) &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;명령어를 입력하면 중지된 컨테이너 ID를 한번에 가져와서 한번에 삭제 가능&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1701585886984&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker rm [OPTIONS] CONTAINER [CONTAINER...]

ex) 종료된 ubuntu, tensorflow 컨테이너 삭제
docker ps -a # get container ID
docker rm ${UBUNTU_CONTAINER_ID} ${TENSORFLOW_CONTAINER_ID}
docker ps -a # check exist&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;images - 이미지 목록 확인하기&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;이미지 주소와 태그, ID, 생성시점, 용량이 보인다.&lt;/li&gt;
&lt;li&gt;이미지가 너무 많이 쌓이면 용량을 차지하기 때문에 사용하지 않는 이미지는 지우는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1701585955173&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker images [OPTIONS] [REPOSITORY[:TAG]]

[output]
REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
wordpress                   latest              b1fe82b15de9        43 hours ago        400.2 MB
redis                       latest              45c3ea2cecac        44 hours ago        182.9 MB
mysql                       5.7                 f3694c67abdb        46 hours ago        400.1 MB
ubuntu                      16.04               104bec311bcd        4 weeks ago         129 MB
teamlab/pydata-tensorflow   0.1                 7bdf5d7e0191        6 months ago        3.081 GB&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;pull - 이미지 다운로드하기&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;run 명령어를 입력하면 이미지가 없을 때 자동으로 다운받지만&lt;/li&gt;
&lt;li&gt;같은 태그지만 이미지가 업데이트 된 경우는 pull 명령어를 통해 새로 다운받을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1701586003140&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker pull [OPTIONS] NAME[:TAG|@DIGEST]

ex) ubuntu:14.04 다운받기
docker pull ubuntu:14.04&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;rmi - 이미지 삭제하기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너가 실행 중인 이미지는 삭제되지 않는다.&lt;/li&gt;
&lt;li&gt;컨테이너는 이미지들의 레이어를 기반으로 실행 중이므로 당연히 삭제 불가!&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1701586039751&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker rmi [OPTIONS] IMAGE [IMAGE...]

ex) tensorflow 이미지 제거
docker images # get image ID
docker rmi ${TENSORFLOW_IMAGE_ID}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컨테이너 둘러보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;logs - 컨테이너 로그 보기&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;--tail 옵션으로 마지막 10줄만 출력할 수 있다.&lt;/li&gt;
&lt;li&gt;-f 옵션으로 로그를 실시간으로 확인할 수 있고 ctrl+c를 입력하면 중지된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1701586114555&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker logs [OPTIONS] CONTAINER

docker ps
docker logs ${WORDPRESS_CONTAINER_ID}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;exec - 컨테이너 명령어 실행하기&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;run 명령어와의 차이점
&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;exec : 실행 중인 컨테이너에 명령어를 내림&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컨테이너 업데이트&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u8AJP/btsBl6v0r5b/xElelPTRRtoh9SkmF9ghgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u8AJP/btsBl6v0r5b/xElelPTRRtoh9SkmF9ghgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u8AJP/btsBl6v0r5b/xElelPTRRtoh9SkmF9ghgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu8AJP%2FbtsBl6v0r5b%2FxElelPTRRtoh9SkmF9ghgK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;416&quot; height=&quot;280&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;450&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;/li&gt;
&lt;li&gt;도터에서 컨테이너를 업데이트하는 과정
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;새 버전의 이미지를 다운(pull) 받고&lt;/li&gt;
&lt;li&gt;기존 컨테이너를 삭제(stop, rm)한 후&lt;/li&gt;
&lt;li&gt;새 이미지를 기반으로 새 컨테이너를 실행(run) 하면 된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;주의&lt;br /&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;이런 상황을 방지하기 위해 컨테이너 삭제 시 유지해야 하는 데이터는 반드시 컨테이너 내부가 아닌 외부 스토리지(AWS S3 같은 클라우드 서비스나 데이터 볼륨을 컨테이너에 추가)에 저장해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Infra/Docker</category>
      <author>chchae01</author>
      <guid isPermaLink="true">https://chchae01.tistory.com/94</guid>
      <comments>https://chchae01.tistory.com/94#entry94comment</comments>
      <pubDate>Sun, 3 Dec 2023 15:55:40 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] Docker란 무엇인가?</title>
      <link>https://chchae01.tistory.com/93</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;604&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBcElZ/btsBla6mQXA/Ta544B3bqEpnMCj2zjpFPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBcElZ/btsBla6mQXA/Ta544B3bqEpnMCj2zjpFPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBcElZ/btsBla6mQXA/Ta544B3bqEpnMCj2zjpFPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBcElZ%2FbtsBla6mQXA%2FTa544B3bqEpnMCj2zjpFPK%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;390&quot; height=&quot;339&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;604&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Docker의 역사&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;등장배경&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 환경은 발전하고 개발자들은 그에 맞춰 계속해서 서버 환경을 업데이트하고 바꿔줘야 한다.&lt;/li&gt;
&lt;li&gt;DevOps(software Development and IT Operations, 개발 및 it 운영 작업의 통합 &amp;amp; 자동화)의 등장으로 개발 주기가 짧아지면서 배포는 더 자주 이루어지고 마이크로 서비스 아키텍처가 유행하면서 프로그램은 더 잘게 조개어져 관리는 더 복잡해진다.&lt;/li&gt;
&lt;li&gt;새로운 툴은 계속해서 나오고 클라우드의 발전으로 설치해야할 서버가 수백, 수천 대에 이르는 상황에서 Docker가 등장하고 서버 관리 방식은 완전히 바뀌게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Docker란?&lt;/h3&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Docker&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;Docker는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;컨테이너 기반의 오픈소스 가상화 플랫폼&lt;/b&gt;&lt;/span&gt;이다.&lt;/li&gt;
&lt;li&gt;컨테이너 : 서버에서 말하는 컨테이너란 다양한 프로그램 실행환경을 컨테이너로 추상화하고 동일한 인터페이스를 제공하여 프로글매의 배포 및 관리를 단순하게 해준다.&lt;/li&gt;
&lt;li&gt;백엔드 프로그램, 데이터베이스 서버, 메시지 큐 등 어떠 ㄴ프로글매도 컨테이너로 추상화할 수 있고, 조립 PC, AWS, Azure, Google cloud 등 어디에서든 실행할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Container&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;span style=&quot;color: #ee2323;&quot;&gt;격리된 공간에서 프로세스가 동작하는 기술&lt;/span&gt;&lt;/b&gt;이다.&lt;/li&gt;
&lt;li&gt;기존의 방식(호스트형 가상화 방식)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OS를 가상화&lt;/li&gt;
&lt;li&gt;VMware나 VirtualBox 같은 가상머신은 호스트 OS 위에 게스트 OS 전체를 가상화하여 사용하는 방식&lt;/li&gt;
&lt;li&gt;여러가시 OS를 가상화할 수 있고 비교적 사용법이 간단하지만 무겁고 느려서 운영 환경에서는 사용할 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;KVN, XEN
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;호스트형 가상화 방식을 개선하기 위해 CPU의 가상화기술을 이용한 &lt;b&gt;KVN&lt;/b&gt;(Kernel-based Virtual Machine)과 반가상화(Paravirtaulization) 방식의 &lt;b&gt;Xen&lt;/b&gt;이 등장&lt;/li&gt;
&lt;li&gt;게스트 OS가 필요하긴 했지만 전체 OS를 가상화하는 방식이 아니기 때문에 호스트형 가상화방식에 비해 성능이 향상되었다.&lt;/li&gt;
&lt;li&gt;클라우드 서비스(OpenStack, AWS, ...)에서 가상 컴퓨팅 기술의 기반&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로세스 격리 방식
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전가상화든 반가상화든 추가적인 OS를 설치하여 가상화하는 방법은 성능 문제가 있었고 이를 개선하기 위해 프로세스 격리 방식이 등장했다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) 리눅스의 '리눅스 컨테이너' 방식
&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;CPU나 메모리는 딱 프로세스가 필요한 만큼만 추가로 사용하고 성능적으로도 거의 손실이 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하나의 서버에 여러개의 컨테이너를 실행하면 독립적으로 실행되어 마치 가벼운 VM을 사용하는 느낌을 준다.&lt;/li&gt;
&lt;li&gt;실행중인 컨테이너에 접속해 명령어를 입력할 수 있고 패키지를 설치할 수 있다.&lt;/li&gt;
&lt;li&gt;CPU나 메모리 사용량을 제한할 수 있다.&lt;/li&gt;
&lt;li&gt;호스트의 특정 포트와 연결하거나 호소트의 디렉토리를 내부 디렉토리인 것처럼 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;새로운 컨테이너를 생성하는 시간은 겨우 1~2초로 가상머신과 비교도 안되게 빠르다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIjidb/btsBjeIur3Z/k1wCurYZLEYc8Inipt76Tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIjidb/btsBjeIur3Z/k1wCurYZLEYc8Inipt76Tk/img.png&quot; data-alt=&quot;VM vs Docker&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIjidb/btsBjeIur3Z/k1wCurYZLEYc8Inipt76Tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIjidb%2FbtsBjeIur3Z%2Fk1wCurYZLEYc8Inipt76Tk%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;467&quot; height=&quot;279&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;450&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;VM vs Docker&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Image&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;/li&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;li&gt;이미지는 컨테이너를 실행하기 위한 모든 정보를 가지고 있기 때문에 더이상 의존성 파일을 컴파일하고 이것저것 설치할 필요가 없다.&lt;/li&gt;
&lt;li&gt;새로운 서버가 추가되면 미리 만들어놓은 이미지(ex. debian을 기반으로 MySQL을 실행하는데 필요한 파일과 실행 명령어, 포트 정보 등을 가짐)를 다운받고 컨테이너(ex. mysql)를 생성만 하면 된다.&lt;/li&gt;
&lt;li&gt;도커 이미지는 Docker Hub에 등록하거나 Docker Registry 저장소를 직접 만들어 관리할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;695&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dns2Km/btsBfLtOHh3/mbzWZJK9uXMLmePg6me8Y0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dns2Km/btsBfLtOHh3/mbzWZJK9uXMLmePg6me8Y0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dns2Km/btsBfLtOHh3/mbzWZJK9uXMLmePg6me8Y0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdns2Km%2FbtsBfLtOHh3%2FmbzWZJK9uXMLmePg6me8Y0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;425&quot; height=&quot;231&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;695&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Docker를 사용하는 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;레이어 저장방식&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;306&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1IuVe/btsBlb5hKjU/0bnv546sSH5LhfRPkwkkR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1IuVe/btsBlb5hKjU/0bnv546sSH5LhfRPkwkkR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1IuVe/btsBlb5hKjU/0bnv546sSH5LhfRPkwkkR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1IuVe%2FbtsBlb5hKjU%2F0bnv546sSH5LhfRPkwkkR0%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;539&quot; height=&quot;217&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;306&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;/li&gt;
&lt;li&gt;도커는 여러 이미지를 효율적으로 저장하기 위해 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;레이어&lt;/b&gt;&lt;/span&gt;라는 개념을 사용해 &lt;span style=&quot;color: #ee2323;&quot;&gt;파일 시스템을 이용하여 여러개의 레이어를 하나의 파일시스템으로 사용할 수 있게 해준다.&lt;/span&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;size18&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;이미지는 url 방식으로 관리하며 태그를 붙일 수 있다.&lt;/li&gt;
&lt;li&gt;이해하기 쉽고 편리하게 사용 가능하다.&lt;/li&gt;
&lt;li&gt;태그 기능을 잘 이용하면 테스트나 롤백도 쉽게 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Dockerfile&lt;/span&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;도커는 이미지를 만들기 위해 Dockerfile이라는 파일 자체 DSL(Domain Specific Language)언어를 이용해 이미지 생성 과정을 적는다.&lt;/li&gt;
&lt;li&gt;과거에는 서버에 어떤 프로그램을 설치하려고 의존성 패키지를 이것저것 설치하고 설정 파일을 만들었다.&lt;/li&gt;
&lt;li&gt;그 과정을 따로 정리하지 않고 Dockerfile로 관리하면&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;소스와 함께 버전 관리 가능!&lt;/li&gt;
&lt;li&gt;누구나 이미지 생성 과정을 보고 수정 가능!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Docker Hub&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;큰 용량의 도커 이미지를 서버에 저장하고 관리하는 것은 쉽지 않다.&lt;/li&gt;
&lt;li&gt;도커는 Docker Hub를 통해 공개 이미지를 무료로 관리해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Command와 API&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도커 클라이언트의 커맨드 명령어는 직관적이고 사용하기 쉽다.&lt;/li&gt;
&lt;li&gt;HTTP 기반의 RestAPI도 지원하여 확장성이 좋고 훌륭한 3rd party 툴이 나오기 좋은 환경이다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Infra/Docker</category>
      <author>chchae01</author>
      <guid isPermaLink="true">https://chchae01.tistory.com/93</guid>
      <comments>https://chchae01.tistory.com/93#entry93comment</comments>
      <pubDate>Sun, 3 Dec 2023 15:13:34 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] 다대다관계</title>
      <link>https://chchae01.tistory.com/92</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;348&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rZ5gd/btsA8sMZpFZ/FVv8EAbT6pagfuN46sfgQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rZ5gd/btsA8sMZpFZ/FVv8EAbT6pagfuN46sfgQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rZ5gd/btsA8sMZpFZ/FVv8EAbT6pagfuN46sfgQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrZ5gd%2FbtsA8sMZpFZ%2FFVv8EAbT6pagfuN46sfgQK%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;348&quot; height=&quot;348&quot; data-origin-width=&quot;348&quot; data-origin-height=&quot;348&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다대다(M:N) 관계란&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 개의 테이블이 서로의 행에 대해서 여러개로 연관되어 있는 상태를 다대다(M:N)관계라 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 하나의 상품이 여러 구성성분들로 이루어져 있고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 구성 성분들은 여러 상품들에 구성되어지는 관계를 말한다.&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체는 컬렉션을 사용해서 객체 2개로 다대다 관계가 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;594&quot; data-origin-height=&quot;219&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/en7yoC/btsA9WNG9T8/JLzuwRrrqKneeG575k8pQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/en7yoC/btsA9WNG9T8/JLzuwRrrqKneeG575k8pQ1/img.png&quot; data-alt=&quot;예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/en7yoC/btsA9WNG9T8/JLzuwRrrqKneeG575k8pQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fen7yoC%2FbtsA9WNG9T8%2FJLzuwRrrqKneeG575k8pQ1%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;594&quot; height=&quot;219&quot; data-origin-width=&quot;594&quot; data-origin-height=&quot;219&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;예시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시처럼 JPA의 @ManyToMany 어노테이션을 사용해 객체의 다대다 관계를 구현하고 테이블 상에서 연결 테이블이 존재하면 된다. 하지만 이 방식을 지양되어져야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조인 테이블 자체에 주문시간, 수량 같은 추가 정보를 넣을 수 없다.&lt;/li&gt;
&lt;li&gt;개발 상에서 연결 테이블이 엔티티로 보이지 않기 때문에 예상하지 못하는 쿼리들이 나간다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 연결 테이블을 엔티티로 승격 시켜야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@ManyToMany를 @ManyToOne, @OneToMany로 풀어 표현하면 유연한 개발이 가능한 다대다 매핑이 완성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 프로젝트에 적용한 내용이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;1092&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/refbC/btsA30DXmfG/SamTj7HtcqzBSL2CHbXhIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/refbC/btsA30DXmfG/SamTj7HtcqzBSL2CHbXhIk/img.png&quot; data-alt=&quot;상품과 성분 엔티티에 대한 다대다 매핑&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/refbC/btsA30DXmfG/SamTj7HtcqzBSL2CHbXhIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrefbC%2FbtsA30DXmfG%2FSamTj7HtcqzBSL2CHbXhIk%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;380&quot; height=&quot;395&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;1092&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;상품과 성분 엔티티에 대한 다대다 매핑&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Ingredient&lt;/h4&gt;
&lt;pre id=&quot;code_1701186812404&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Ingredient {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String description;
    @OneToMany(mappedBy = &quot;ingredient&quot;)
    private List&amp;lt;ProductIngredient&amp;gt; products = new ArrayList&amp;lt;&amp;gt;();
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ProductIngredient&lt;/h4&gt;
&lt;pre id=&quot;code_1701186868441&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class ProductIngredient {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = &quot;product_id&quot;)
    private Product product;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = &quot;ingredient_id&quot;)
    private Ingredient ingredient;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Product&lt;/h4&gt;
&lt;pre id=&quot;code_1701186884057&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    
    ...
    
    @OneToMany(mappedBy = &quot;product&quot;)
    private List&amp;lt;ProductIngredient&amp;gt; ingredients = new ArrayList&amp;lt;&amp;gt;();
}&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;a href=&quot;https://ict-nroo.tistory.com/127&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고 블로그&lt;/a&gt;&lt;/p&gt;</description>
      <category>Spring/JPA</category>
      <author>chchae01</author>
      <guid isPermaLink="true">https://chchae01.tistory.com/92</guid>
      <comments>https://chchae01.tistory.com/92#entry92comment</comments>
      <pubDate>Wed, 29 Nov 2023 00:55:40 +0900</pubDate>
    </item>
    <item>
      <title>[SpringDataJPA] SpringDataJPA란?</title>
      <link>https://chchae01.tistory.com/91</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;315&quot; data-origin-height=&quot;160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/braVbz/btsAUH5LdUX/Cmo6kuoDguPBNSO4DQa4PK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/braVbz/btsAUH5LdUX/Cmo6kuoDguPBNSO4DQa4PK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/braVbz/btsAUH5LdUX/Cmo6kuoDguPBNSO4DQa4PK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbraVbz%2FbtsAUH5LdUX%2FCmo6kuoDguPBNSO4DQa4PK%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;315&quot; height=&quot;160&quot; data-origin-width=&quot;315&quot; data-origin-height=&quot;160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JPA란?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA는 자바 ORM(Object Relational Mapping) 기술에 대한 API 표준 명세를 말한다.&lt;/li&gt;
&lt;li&gt;여기서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ORM 기술&lt;/b&gt;&lt;/span&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;객체는 객체대로, 관계형 데이터베이스는 관계형 데이터베이스대로 설계하고, ORM 프레임워크가 중간에서 매핑해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JPA는 라이브러리가 아닌 ORM을 사용하기 위한 인터페이스의 모음이다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA는 인터페이스의 모음, 단순한 명세이기 때문에 구현이 없다.&lt;/li&gt;
&lt;li&gt;자바 애플리케이션에서 관계형 데이터베이스를 어떻게 사용할 지 정의하는 하나의 방법일 뿐이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서! JPA의 구현체가 있어야 JPA를 사용할 수 있다.&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;Hibernate란?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Hibernate는 JPA를 구현한 구현체이다.&lt;/li&gt;
&lt;li&gt;개발된 지 10년이 넘은 대중적인 JPA 구현체 중 하나이다.&lt;/li&gt;
&lt;li&gt;JPA의 핵심들인 EntityManagerFactory, EntityManager, EntityTransaction 등을 상속받아 구현한다.&lt;/li&gt;
&lt;li&gt;JPA를 구현하는 다른 구현체들로는 EclipseLink나 DataNucleus 등이 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개발자가 직접 JPA 구현체를 만들어 사용할 수도 있음!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Hibernate는 내부적으로 JDBC(Java Database COnnectivity)를 이용해 관계형 데이터베이스와 커넥션을 맺고 상호작용을 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Spring Data JPA란?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring Data JPA는 JPA를 사용하기 편하도록 만들어놓은 모듈이다.&lt;/li&gt;
&lt;li&gt;Spring Data JPA는 JPA를 한단계 더 추상화시킨 Repository 인터페이스를 제공하고 Hibernate와 같은 JPA 구현체를 사용해서 JPA를 사용하게 된다.&lt;/li&gt;
&lt;li&gt;Spring Data JPA를 사용하면 사용자는 더욱 간단하게 데이터 접근이 가능해진다.&lt;/li&gt;
&lt;/ul&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;JPA&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바 진영의 ORM 기술에 대한 API 표준 명세&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Hibernate&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA의 구현체&lt;/li&gt;
&lt;li&gt;내부적으로 JDBC를 이용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Spring Data JPA&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA를 이용하기 쉽게 스프링에서 제공하는 모듈&lt;/li&gt;
&lt;li&gt;내부적으로 JPA 구현체를 이용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://code-lab1.tistory.com/288&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고 블로그&lt;/a&gt;&lt;/p&gt;</description>
      <category>Spring/JPA</category>
      <author>chchae01</author>
      <guid isPermaLink="true">https://chchae01.tistory.com/91</guid>
      <comments>https://chchae01.tistory.com/91#entry91comment</comments>
      <pubDate>Mon, 27 Nov 2023 17:20:52 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] 연관관계 매핑</title>
      <link>https://chchae01.tistory.com/90</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;348&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u4hr1/btsASSTPzGa/0Wr3TuMEgXYBvOHDClKJ20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u4hr1/btsASSTPzGa/0Wr3TuMEgXYBvOHDClKJ20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u4hr1/btsASSTPzGa/0Wr3TuMEgXYBvOHDClKJ20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu4hr1%2FbtsASSTPzGa%2F0Wr3TuMEgXYBvOHDClKJ20%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;348&quot; height=&quot;348&quot; data-origin-width=&quot;348&quot; data-origin-height=&quot;348&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;객체 지향 프로그램&lt;/b&gt;에서의 객체와 RDB에서의 테이블이 서로 연관관계를 맺는 방법이 다르다.&lt;br /&gt;따라서 이 둘의 차이를 채우기 위한 매핑 과정이 필요하고 이를 ORM인 JPA가 수행하게 된다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ORM이란?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;영속성(Persistence)&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;Object Persistence(영구적인 객체) : 메모리 상의 데이터를 파일 시스템, 관계형 데이터베이스 혹은 객체 데이터베이스 등을 활용해 영구적으로 저장하여 영속성을 부여한다.&lt;/li&gt;
&lt;li&gt;JDBC, Spring JDBC(ex. jdbcTemplate), Persistence Framework(ex. Hibernate, Mybatis)를 활용해 데이터를 데이터베이스에 영구적으로 저장할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;ORM이란?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Object Relational Mapping, 객체-관계 매핑&lt;/li&gt;
&lt;li&gt;객체와 관계형 데이터 베이스의 데이터를 자동으로 매핑(연결)해주는 것을 말한다.&lt;/li&gt;
&lt;li&gt;Persistence API라고도 할 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;ex) JPA, Hibernate&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://gmlwjd9405.github.io/2019/02/01/orm.html&quot;&gt;ORM이란&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;데이터 중심의 모델링&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체를 RDB의 테이블에 맞춰 데이터 중심적으로 모델링할 경우 객체 지향 프로그래밍에서의 객체를 제대로 활용할 수 없다.&lt;br /&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;p data-ke-size=&quot;size16&quot;&gt;또한 해당 객체를 테이블에 저장하고 읽어오는 과정에서 여러가지 단점들이 있다.&lt;br /&gt;예를 들어 &lt;code&gt;Member&lt;/code&gt;와 &lt;code&gt;Team&lt;/code&gt; 엔티티에 대한 코드를 데이터 중심 설계로 작성할 경우&lt;/p&gt;
&lt;pre id=&quot;code_1701000562495&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Member {
    private long id;
    private long teamId;
    private String userName;
}

class Team {
    private long id;
    private String teamName;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;member의 team 정보를 알기 위해서는 member를 조회한 뒤 외래키로 가지고 있는 teamId를 통해서 team을 조외하는 과정을 반복해야 한다.&lt;br /&gt;즉 member를 조회하는 쿼리와 team을 조회하는 쿼리 총 2개가 필요하게 된다.&lt;br /&gt;위의 예시는 간단하지만 연관관계가 많아지면 아주 복잡해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;연관관계 매핑&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러가지 연관관계에서 객체와 데이터베이스의 테이블이 각각 어떻게 연관관계를 가지는지 살펴보자&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 단방향 연관관계&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체
&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;A가 B를 참조할 때 B-&amp;gt;A는 불가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;테이블&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외래키로 join해 연관된 테이블을 조회한다.&lt;/li&gt;
&lt;li&gt;양방향으로 A-&amp;gt;B, B-&amp;gt;A 모두 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/derTKX/btsAZ9fo0kh/2lTZIY7nAZKEILsyG9esB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/derTKX/btsAZ9fo0kh/2lTZIY7nAZKEILsyG9esB0/img.png&quot; data-alt=&quot;테이블의 연관관계&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/derTKX/btsAZ9fo0kh/2lTZIY7nAZKEILsyG9esB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FderTKX%2FbtsAZ9fo0kh%2F2lTZIY7nAZKEILsyG9esB0%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;652&quot; height=&quot;185&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;256&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;테이블의 연관관계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단방향 연관관계에서는 객체와 데이터베이스의 테이블은 연관관계를 맺을 때 위와 같은 차이가 존재한다. 이를 극복하기 위해 객체를 데이터에 맞추어야 한다. 아래는 **객체 중심의 모델링**을 따른 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1701000581991&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Memeber {
    @Id @GeneratedValue
    private Long id;
    
    private String userName;
    
    @ManyToOne
    @JoniColumn(name = &quot;team_id&quot;)
    private Team team;
}

@Entity
public class Team {
    @Id @GeneratedValue
    private Long id;
    
    private String teamName;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 ORM을 활용하면 member 조회 시 연관관계를 가지는 team 까지 가져와 객체 참조 형태로 매핑까지 해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1701000701607&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void find(Long memberId) {
    	EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        
        tx.begin();
        try {
            // findMember 를 가져올 때 연관관계를 가지는 Team 까지 가져와서 객체 참조형태로 매핑까지 해준다.
            Member findMember = em.find(Member.class, memberId);
            Team findTeam = findMember.getTeam();
            
            tx.commit();
        } catch(Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 양방향 연관관계&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 양방향 연관관계는 없다! 그냥 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;두 객체가 서로 참조하는 단방향 연관관계가 2개인 것을 양방향 연관관계&lt;/b&gt;&lt;/span&gt;라 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체에서 양방향 연관관계란 단방향 연관관계 2개를 말하기 때문에 데이터베이스 테이블과의 차이점이 발생하고 이러한 차이점을 극복하기 위한 것이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;양방향 연관관계 매핑&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체에는 두 개의 단방향 연관관계가 있고, 테이블에는 하나의 양방향 연관관계가 있다. 그럼 DB의 관점에서 Member 객체의 team을 수정해도 외래키인 TEAM_ID가 수정되어야 하고, Team의 members를 수정해도 외래키인 TEAM_ID가 수정되어야 한다. 다시 말해 MEMBER 테이블의 외래키 TEAM_ID는 두개의 연관관계 매핑에 엮여 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 문제를 해결하기 위해 양방향 연관관계 매핑에서는 해당 연관관계의 주인을 결정해 객체의 두 개의 단방향 연관관계 중 외래키 TEAM_ID에 영향을 줄 하나의 단방향 연관관계를 지정해줘야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1701001666805&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Member {
    @Id @GeneratedValue
    private Long id;
    
    private String memberName;
    
    @ManyToOne
    @JoinColumn(&quot;team_id&quot;)
    private Team team;
}

@Entity
public class Team {
    @Id @GeneratedValue
    private Long id;
    
    private String teamName;
    
    @OneToMany(mappedBy = &quot;team&quot;)
    List&amp;lt;Member&amp;gt; members = new ArrayList&amp;lt;&amp;gt;();
}&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;@OneToMany 어노테이션의 mappedBy 값인 team을 가지고 있는 Member&lt;/b&gt;&lt;/span&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt; @OneToMany(mappedBy=&quot;team&quot;)의 의미는 team이라는 것에 매핑한다는 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연관관계 매핑의 주인이 정해지면 아래의 규칙이 생긴다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;1. 연관관계 매핑의 주인만이 외래키를 관리한다.(등록 &amp;amp; 수정)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;2. 주인이 아닌 쪽에서는 오직 읽기만 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;3. 주인은 mappedBy 속성을 사용하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;4 주인이 아닌 쪽에서는 mappedBy 속성을 통해 주인을 지정해줘야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이제 테이블에 수정한 값을 반영하려면 반드시 연관관계 매핑의 주인의 값을 변경해줘야 한다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;그럼 두 객체 중 어떤 걸로 연관관계 매핑의 주인을 지정해야 할까?&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;외래키를 가지고 있는 테이블을 연관관계 매핑을 주인을 설정&lt;/b&gt;하면 된다.(혼동 방지를 위한 권장 사항임)&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;참고 블로그&quot; href=&quot;https://ch4njun.tistory.com/274&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고 블로그&lt;/a&gt;&lt;/p&gt;</description>
      <category>Spring/JPA</category>
      <author>chchae01</author>
      <guid isPermaLink="true">https://chchae01.tistory.com/90</guid>
      <comments>https://chchae01.tistory.com/90#entry90comment</comments>
      <pubDate>Sun, 26 Nov 2023 21:39:08 +0900</pubDate>
    </item>
    <item>
      <title>2. 실행 흐름 이해하기</title>
      <link>https://chchae01.tistory.com/89</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;386&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zCWa5/btsATfVDPAd/cx42JJvp4UTkCneGA83Dp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zCWa5/btsATfVDPAd/cx42JJvp4UTkCneGA83Dp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zCWa5/btsATfVDPAd/cx42JJvp4UTkCneGA83Dp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzCWa5%2FbtsATfVDPAd%2Fcx42JJvp4UTkCneGA83Dp0%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;386&quot; height=&quot;225&quot; data-origin-width=&quot;386&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 실행 과정&lt;/h2&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;package.json&lt;/code&gt; 은 해당 프로젝트를 관리하는 설정 파일&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;npm start&lt;/code&gt; 시 &lt;code&gt;index.js&lt;/code&gt;를 실행시킴&lt;br /&gt;&lt;b&gt;package.json&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt; &quot;scripts&quot;: {
 &quot;start&quot;: &quot;react-scripts start&quot;,
 &quot;build&quot;: &quot;react-scripts build&quot;,
 &quot;test&quot;: &quot;react-scripts test&quot;,
 &quot;eject&quot;: &quot;react-scripts eject&quot;
},&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;index.js의 ReactDOM.render() 함수가 실행되는데 이때 render 함수를 통해 페이지의 그림이 그려진다.&lt;br /&gt;&lt;b&gt;index.js&lt;/b&gt;에 렌더링할 함수 존재&lt;/li&gt;
&lt;li&gt;&lt;code&gt;//0. React 엔진 - 데이터 변경 감지해서 UI 그려주는!!
// 1. 실행과정(index.html) - SPA(Single Page Application)
// 2. JSX 문법
function App() {
 return &amp;lt;div&amp;gt;안녕1&amp;lt;/div&amp;gt;;
   // function에 들어가는 문법은 jsx 문법
}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt; const root = ReactDOM.createRoot(document.getElementById('root'));
 root.render(
        &amp;lt;App /&amp;gt; // JSX 문법
 document.querySelector('#root')// index.html 에서 id가 root인 것을 찾아 위의 렌더링 함수의 return 값을 집어넣는다.
 );&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>React/intro</category>
      <author>chchae01</author>
      <guid isPermaLink="true">https://chchae01.tistory.com/89</guid>
      <comments>https://chchae01.tistory.com/89#entry89comment</comments>
      <pubDate>Fri, 24 Nov 2023 14:32:01 +0900</pubDate>
    </item>
  </channel>
</rss>