<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>아주 조금씩 천천히 살짝</title>
    <link>https://peonyf.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 19 May 2026 04:50:40 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>PeonyF</managingEditor>
    <item>
      <title>[FastAPI]  SQLAlchemy orm과 schema</title>
      <link>https://peonyf.tistory.com/entry/FastAPI-SQLAlchemy-orm%EA%B3%BC-schema</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;ORM(Object-Relational Mapping)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot;&gt;데이터베이스를 사용하려면 SQL 쿼리(query)라는 구조화된 질의를 작성하고 실행하는 등의 복잡한 과정이 필요하다. 이때 ORM(object relational mapping)을 이용하면 파이썬 문법만으로도 데이터베이스를 다룰 수 있다. 즉, ORM을 이용하면 개발자가 쿼리를 직접 작성하지 않아도 데이터베이스의 데이터를 처리할 수 있다.(&lt;/span&gt;&lt;a style=&quot;color: #333333;&quot; href=&quot;https://wikidocs.net/book/8531&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;점프 투 FastAPI)&lt;/b&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스의 테이블을 파이썬 객체로 매핑하여 SQL 쿼리 없이 데이터베이스와 상호작용할 수 있게 해주는 방식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; &lt;b&gt;DB의 테이블과 관계를 파이썬 클래스로 정의&lt;/b&gt;&lt;/p&gt;
&lt;h3 id=&quot;sqlalchemy-db-model-생성&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;sqlalchemy db model 생성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;declarative_base()&lt;span&gt;&amp;nbsp;&lt;/span&gt;로&lt;span&gt;&amp;nbsp;&lt;/span&gt;Base&lt;span&gt;&amp;nbsp;&lt;/span&gt;class (sqlalchemy model) 생성&lt;/li&gt;
&lt;li&gt;Base&lt;span&gt;&amp;nbsp;&lt;/span&gt;class로부터 상속받아 db 에 해당하는 model class(model) 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710749078159&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sqlalchemy import Boolean, Column, Integer, String
from sqlalchemy.orm import declarative_base

from schema.request import CreateToDoRequest

Base = declarative_base()

'''
ORM: DB Table에 mapping 할 수 있는 형태의 객체를 만들어서 관리하는 방식
직접 SQL 쿼리를 작성하지 않고 파이썬 코드로 SQL쿼리를 생성해 자동으로 연결시켜줌
'''


class ToDo(Base):
    __tablename__ = &quot;todo&quot;

    id = Column(Integer, primary_key=True, index=True)
    contents = Column(String(256), nullable=False)
    is_done = Column(Boolean, nullable=False)

    def __repr__(self):
        return f&quot;ToDo(id={self.id},contents={self.contents},is_done={self.is_done}&quot;

    @classmethod
    def create(cls,request:CreateToDoRequest) -&amp;gt; &quot;ToDo&quot;:
        return cls(
            contents=request.contents,
            is_done=request.is_done,
        )&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;Schema(Pydantic 모델)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 파싱 과 검증,직렬화,역직렬화를 위해 사용되는 구조. 입력 데이터의 유효성 검사,데이터 변환 등에 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; API로 부터 받은 데이터가 특정 스키마와 일치하는지, 모델에 정의된 타입과 일치하는지 자동 검증&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Pydantic Schema 생성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pydantic의 BaseModel 모듈 이용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710748755583&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from pydantic import BaseModel
from typing import List


class ToDoSchema(BaseModel):
    id: int
    contents: str
    is_done: bool

    class Config: # 외부 클래스의 동작을 구성하거나 커스터마이징하는 데 사용 주로 이름이 Config,Meta
        # orm_mode = True pydatic v1
        from_attributes = True #ORM 모델로부터 Pydantic 모델로 데이터를 변환할 때 필요한 설정


class ToDoListSchema(BaseModel):
    todos: List[ToDoSchema]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ORM과 Schema를 따로 관리하는 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ORM은 db의 table구조와 직접적인 상호작용에사용 (ex.db와의 연동)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Schema는 API의 데이터 구조와 유효성 검사(사용자의 입력이나 API 응답 데이터 형식 정의)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 분리하여 DB의 내부 구조가 변경되더라도 Schema에 영향을 미치지 않아 결합도를 낮출 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;진행과정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. SQLAlchemy를 사용해서 DB모델 정의 및 DB쿼리 실행&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DB 테이블과 맵핑되는 모델 정의&lt;/li&gt;
&lt;li&gt;SQLAlchemy세션을 통해 DB쿼리 실행, 결과를 ORM객체로 받음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Pydantic모델을 사용하여 데이터 검증 및 직렬화&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API로 받은 데이터를 Pydantic 모델로 변환하여 데이터의 유효성을 검사&lt;/li&gt;
&lt;li&gt;SQLAlchemy객체를 Pydantic모델로 변환하여 API response로 리턴&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710750914032&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from pydantic import BaseModel

# SQLAlchemy 모델 정의
Base = declarative_base()
class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    age = Column(Integer)

# Pydantic 모델 정의
class UserSchema(BaseModel):
    id: int
    name: str
    age: int

# SQLAlchemy 세션 생성 및 데이터베이스 쿼리
engine = create_engine('sqlite:///mydatabase.db')
Session = sessionmaker(bind=engine)
session = Session()
user = session.query(User).first()

# SQLAlchemy 객체를 Pydantic 모델로 변환
user_schema = UserSchema.from_orm(user)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;실전! FastAPI 입문 - 인프런&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://wikidocs.net/175967&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://wikidocs.net/175967&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://wikidocs.net/176222&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://wikidocs.net/176222&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://fastapi.tiangolo.com/tutorial/sql-databases/#orms&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://fastapi.tiangolo.com/tutorial/sql-databases/#orms&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@crosstar1228/FastapiSQLAlchemy-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-DB%EC%99%80-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@crosstar1228/FastapiSQLAlchemy-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-DB%EC%99%80-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0&lt;/a&gt;&lt;/p&gt;</description>
      <category>FastAPI</category>
      <author>PeonyF</author>
      <guid isPermaLink="true">https://peonyf.tistory.com/211</guid>
      <comments>https://peonyf.tistory.com/entry/FastAPI-SQLAlchemy-orm%EA%B3%BC-schema#entry211comment</comments>
      <pubDate>Mon, 18 Mar 2024 20:43:25 +0900</pubDate>
    </item>
    <item>
      <title>[Python] API 문법(Response Model), 딕셔너리 언패킹,튜플 언패킹</title>
      <link>https://peonyf.tistory.com/entry/Python-API-%EB%AC%B8%EB%B2%95Response-Model-%EB%94%95%EC%85%94%EB%84%88%EB%A6%AC-%EC%96%B8%ED%8C%A8%ED%82%B9%ED%8A%9C%ED%94%8C-%EC%96%B8%ED%8C%A8%ED%82%B9</link>
      <description>&lt;pre id=&quot;code_1710751650892&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#Pydantic Schema 
from pydantic import BaseModel
from typing import List, Optional
from fastapi import FastAPI, HTTPException, Depends
from sqlalchemy.orm import Session

app = FastAPI()

class BookSchema(BaseModel):
    id: int
    title: str
    author: str
    is_available: bool
    genre:str|None&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1710751492945&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#특정 저자의 모든 책 조회
@app.get(&quot;/books/author/{author_name}&quot;, response_model=List[BookSchema])
def get_books_by_author(author_name: str, session: Session = Depends(get_db)) -&amp;gt; List[BookSchema]:
    books = session.query(Book).filter(Book.author == author_name).all()
    if books:
        return [BookSchema(**book.__dict__) for book in books]
    raise HTTPException(status_code=404, detail=&quot;No books found by this author&quot;)&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;b&gt;1. author_name: str, session: Session = Depends(get_db) 이란?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&amp;nbsp; &amp;nbsp; author_name는 str, session은 get_db()함수로 부터 db세션을 객체로 받아 session 매개변수로 넘긴다.&lt;/li&gt;
&lt;li&gt;&amp;nbsp; &amp;nbsp; ex) name: str = &quot;Alice&quot; 이면 name변수가 str타입으로 명시, 초기값이 Alice&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;b&gt;2. -&amp;gt; List[BookSchema] 혹은&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;def &lt;span style=&quot;color: #8a3db6;&quot;&gt;get_books_by_author&lt;/span&gt;(author_name: str, session: Session = Depends(get_db)) -&amp;gt; BookSchema: 이란?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;get_books_by_author&lt;/span&gt;의결과값으로 BookSchema의 값을 받는다.&lt;/li&gt;
&lt;li&gt;List[BookSchema]의경우 여러개를 받겠다 라는 뜻&lt;/li&gt;
&lt;li&gt;위의 코드의 경우 List[BookSchema]: books = ~ 이므로 &lt;span style=&quot;color: #8a3db6;&quot;&gt;get_books_by_author&lt;/span&gt;의결과값으로 BookSchema값을 받는데 이 BookSchema는 books로 된 객체로 특정 저자의 모든책을 조회한 결과값(session.query(Book).filter(Book.author == author_name).all())이다.&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;b&gt;3.books:Book|None = session.query(Book).filter(Book.author == author_name).all() 이란?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Book|None : 특정 저자의 모든책을 조회한 결과값이 Book 객체거나 없을 경우 None으로 전달&lt;/li&gt;
&lt;li&gt;session.query(Book).filter(Book.author == author_name).all() : 특정 저자의 모든책을 조회한 결과값&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;b&gt;4. [BookSchema(**book.__dict__) for book in books] 이란?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;딕셔너리 언패킹: 객체의 속성을 함수,클래스 생성자에 전달 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710754562286&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def print_info(name, city):
    print(f&quot;Name: {name}, City: {city}&quot;)

info = {'name': 'chacha', 'age': 25, 'city': 'Seoul'}

#key는 새 딕셔너리에 포함될 각 키(key), info[key]는 해당 키에 대응되는 값을(value) 가져옴
filtered_info = {key: info[key] for key in info if key in ['name', 'city']}
print_info(**filtered_info)

#만약 infos일경우 리스트 컴프리헨션 + 딕셔너리 컴프리헨션을 결합해서 사용
infos = [
    {'name': 'chacha', 'age': 25, 'city': 'Seoul'},
    {'name': 'chacha2', 'age': 26, 'city': 'London'},
    {'name': 'chacha3', 'age': 27, 'city': 'New York'}
]
filtered_infos = [{key: info[key] for key in info if key in ['name', 'city']} for info in infos]&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;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;book.__dict__ : book 객체의 속성들을 포함하는 딕셔너리를 반환&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;** 연산자 : &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;book.__dict__를 언패킹하여 BookSchema에 전달(book 객체의 모든 속성이 전달됨)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710753012562&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Book 객체 생성
book = Book(id=1,title=&quot;python&quot;,author=&quot;chacha&quot;,is_abailable=True,genre=&quot;IT&quot;)

# Book 객체의 속성을 BookSchema의 인스턴스로 변환
book_schema = BookSchema(**book.__dict__)&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;/ul&gt;
&lt;pre id=&quot;code_1710753148154&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def print_values(a, b, c):
    print(a, b, c)

values = (1, 2, 3)

#튜플 언패킹
print_values(*values)&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;BookSchema(*book.__dict__)&lt;span&gt; 가 불가능한 이유 : * 연산자의 경우 위치기반의 언패킹으로 딕셔너리에 사용 불가, ** 연산자는 키-값을 키워드 인자로 언패킹하는데 사용&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;5. 새 책 추가(Post)&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1710753515833&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@app.post(&quot;/books&quot;, response_model=BookSchema)
def add_new_book(book_data: BookSchema, session: Session = Depends(get_db)) -&amp;gt; BookSchema:
    book = Book(**book_data.dict())
    session.add(book)
    session.commit()
    session.refresh(book)
    return BookSchema(**book.__dict__)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;열혈&amp;nbsp;파이썬&amp;nbsp;중급&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;&lt;a href=&quot;https://docs.sqlalchemy.org/en/20/orm/session_api.html#sqlalchemy.orm.Session.query&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.sqlalchemy.org/en/20/orm/session_api.html#sqlalchemy.orm.Session.query&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1710753428304&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Session API
 &amp;mdash;
    SQLAlchemy 2.0 Documentation&quot; data-og-description=&quot;Session API Session and sessionmaker() class sqlalchemy.orm.sessionmaker A configurable Session factory. The sessionmaker factory generates new Session objects when called, creating them given the configurational arguments established here. e.g.: from sqla&quot; data-og-host=&quot;docs.sqlalchemy.org&quot; data-og-source-url=&quot;https://docs.sqlalchemy.org/en/20/orm/session_api.html#sqlalchemy.orm.Session.query&quot; data-og-url=&quot;https://docs.sqlalchemy.org/en/20/orm/session_api.html#sqlalchemy.orm.Session.query&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.sqlalchemy.org/en/20/orm/session_api.html#sqlalchemy.orm.Session.query&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.sqlalchemy.org/en/20/orm/session_api.html#sqlalchemy.orm.Session.query&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Session API &amp;mdash; SQLAlchemy 2.0 Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Session API Session and sessionmaker() class sqlalchemy.orm.sessionmaker A configurable Session factory. The sessionmaker factory generates new Session objects when called, creating them given the configurational arguments established here. e.g.: from sqla&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.sqlalchemy.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Python</category>
      <author>PeonyF</author>
      <guid isPermaLink="true">https://peonyf.tistory.com/212</guid>
      <comments>https://peonyf.tistory.com/entry/Python-API-%EB%AC%B8%EB%B2%95Response-Model-%EB%94%95%EC%85%94%EB%84%88%EB%A6%AC-%EC%96%B8%ED%8C%A8%ED%82%B9%ED%8A%9C%ED%94%8C-%EC%96%B8%ED%8C%A8%ED%82%B9#entry212comment</comments>
      <pubDate>Mon, 18 Mar 2024 20:19:02 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm] 백준 16933의 메모리 초과</title>
      <link>https://peonyf.tistory.com/entry/Algorithm-%EB%B0%B1%EC%A4%80-16933%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%B4%88%EA%B3%BC</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;기존 코드&lt;/p&gt;
&lt;pre id=&quot;code_1708649199142&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#16933
import sys
from collections import deque

n, m, break_cnt = map(int, input().split())
graph = [list(map(int, input())) for _ in range(n)]
visited = [[[False] * (break_cnt + 1) for _ in range(m)] for _ in range(n)]

dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]


def bfs():
    queue = deque()
    queue.append((0, 0, 0, 1, 1))  # 시작 위치, 벽을 부순 횟수, 이동 거리 추가,밤낮여부(낮:1,밤:0)
    visited[0][0][0] = 1
    
    while queue:
        x, y, cur_break_cnt, distance, is_day = queue.popleft()

        # 도착 지점에 도달했을 경우
        if x == (n - 1) and y == (m - 1):
            return distance

        # 인접한 네 방향 탐색
        for i in range(4):
            nx = dx[i] + x
            ny = dy[i] + y

            # 범위 내에 있을 경우
            if 0 &amp;lt;= nx &amp;lt; n and 0 &amp;lt;= ny &amp;lt; m:
                # 벽이 있고, 벽을 부술 수 있으며, 방문하지 않은 경우
                if graph[nx][ny] == 1 and cur_break_cnt &amp;lt; break_cnt and not visited[nx][ny][cur_break_cnt + 1]:
                    if is_day:  # 낮인 경우
                        queue.append((nx, ny, cur_break_cnt + 1, distance + 1, 0))
                        visited[nx][ny][cur_break_cnt + 1] = True
                    else:
                        queue.append((x, y, cur_break_cnt, distance + 1, 1))

                # 벽이 없고 방문하지 않은 경우
                elif graph[nx][ny] == 0 and not visited[nx][ny][cur_break_cnt]:
                    visited[nx][ny][cur_break_cnt] = True
                    if is_day:
                        queue.append((nx, ny, cur_break_cnt, distance + 1, 0))
                    else:
                        queue.append((nx, ny, cur_break_cnt, distance + 1, 1))
    return -1


print(bfs())&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;pre id=&quot;code_1708649213675&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#16933
import sys
from collections import deque

n, m, break_cnt = map(int, input().split())
graph = [list(map(int, input())) for _ in range(n)]
visited = [[[0] * m for _ in range(n)] for _ in range(break_cnt + 1)]

dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]


def bfs():
    queue = deque()
    queue.append((0, 0, 0, 1, 1))  # 시작 위치, 벽을 부순 횟수, 이동 거리 추가,밤낮여부(낮:1,밤:0)
    visited[0][0][0] = 1
    
    while queue:
        x, y, cur_break_cnt, distance, is_day = queue.popleft()

        # 도착 지점에 도달했을 경우
        if x == (n - 1) and y == (m - 1):
            return distance

        # 인접한 네 방향 탐색
        for i in range(4):
            nx = dx[i] + x
            ny = dy[i] + y

            # 범위 내에 있을 경우
            if 0 &amp;lt;= nx &amp;lt; n and 0 &amp;lt;= ny &amp;lt; m:
                # 벽이 있고, 벽을 부술 수 있으며, 방문하지 않은 경우
                if graph[nx][ny] == 1 and cur_break_cnt &amp;lt; break_cnt and not visited[cur_break_cnt + 1][nx][ny]:
                    if is_day:  # 낮인 경우
                        queue.append((nx, ny, cur_break_cnt + 1, distance + 1, 0))
                        visited[cur_break_cnt + 1][nx][ny] = 1
                    else:
                        queue.append((x, y, cur_break_cnt, distance + 1, 1))

                # 벽이 없고 방문하지 않은 경우
                elif graph[nx][ny] == 0 and not visited[cur_break_cnt][nx][ny]:
                    visited[cur_break_cnt][nx][ny] = 1
                    if is_day:
                        queue.append((nx, ny, cur_break_cnt, distance + 1, 0))
                    else:
                        queue.append((nx, ny, cur_break_cnt, distance + 1, 1))
    return -1


print(bfs())&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차이점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 메모리 접근 패턴이 다름&lt;/p&gt;
&lt;pre id=&quot;code_1708649320361&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 기존코드
visited = [[[False] * (break_cnt + 1) for _ in range(m)] for _ in range(n)]
 if graph[nx][ny] == 1 and cur_break_cnt &amp;lt; break_cnt and not visited[nx][ny][cur_break_cnt + 1]:
    if is_day:  # 낮인 경우
       queue.append((nx, ny, cur_break_cnt + 1, distance + 1, 0))
       visited[nx][ny][cur_break_cnt + 1] = True
       
# 바뀐코드

visited = [[[0] * m for _ in range(n)] for _ in range(break_cnt + 1)]
 if graph[nx][ny] == 1 and cur_break_cnt &amp;lt; break_cnt and not visited[cur_break_cnt + 1][nx][ny]:
    if is_day:  # 낮인 경우
       queue.append((nx, ny, cur_break_cnt + 1, distance + 1, 0))
       visited[cur_break_cnt + 1][nx][ny] = 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존코드 메모리 참조 방식 (불연속적 접근):&amp;nbsp; &amp;nbsp;visited[0][0][0]에서 visited[0][0][1]로 점프해야함 -&amp;gt; &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;캐시 활용이 덜 효율적임&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1708649650305&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;visited[0][0][0], visited[0][0][1], visited[0][1][0], visited[0][1][1], visited[0][2][0], visited[0][2][1], visited[1][0][0], visited[1][0][1], visited[1][1][0], visited[1][1][1], visited[1][2][0], visited[1][2][1], visited[2][0][0], visited[2][0][1], visited[2][1][0], visited[2][1][1], visited[2][2][0], visited[2][2][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;바뀐코드 메모리 참조 방식(연속적 접근): cur_break_cnt값에 대해 (x,y)를 순회하며 메모리에 연속 접근함 -&amp;gt; &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt; 캐시 효율성을 높일 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1708649899157&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 벽을 부수지 않고 방문한 경우(0회 부숨): 
visited[0][0][0], visited[0][0][1], visited[0][0][2], visited[0][1][0], visited[0][1][1], visited[0][1][2], visited[0][2][0], visited[0][2][1], visited[0][2][2]
# 벽을 부수고 방문한 경우(1회 부숨): 
visited[1][0][0], visited[1][0][1], visited[1][0][2], visited[1][1][0], visited[1][1][1], visited[1][1][2], visited[1][2][0], visited[1][2][1], visited[1][2][2]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;연속된 접근 vs. 불연속적인 접근&lt;/h3&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;background-color: #f7f7f7; border: #c1c1c1 1px solid; padding: 10px;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연속된 접근: 순차적으로 데이터를 읽을 경우 메모리의 연속된 주소를 차례대로 접근함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; CPU캐시가 이러한 접근 패턴을 예측하고, 미리 다음에 필요할 데이터를 미리 캐시에 로드함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불연속적인 접근: 빈번하게 점프하며 데이터에 접근하는 경우&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; CPU캐시가 예측을 할 수 없어 미리 데이터를 로드하기 어려움. 캐시미스 발생(CPU가 메인메모리에 직접 접근해, 메모리 대기 시간이 증가시킴)&lt;/p&gt;
&lt;/div&gt;</description>
      <category>Algorithms</category>
      <author>PeonyF</author>
      <guid isPermaLink="true">https://peonyf.tistory.com/209</guid>
      <comments>https://peonyf.tistory.com/entry/Algorithm-%EB%B0%B1%EC%A4%80-16933%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%B4%88%EA%B3%BC#entry209comment</comments>
      <pubDate>Fri, 23 Feb 2024 10:27:30 +0900</pubDate>
    </item>
    <item>
      <title>[DOCKER] Docker compose에 nginx 적용기</title>
      <link>https://peonyf.tistory.com/entry/DOCKER-Docker-compose%EC%97%90-nginx-%EC%A0%81%EC%9A%A9%EA%B8%B0</link>
      <description>&lt;h1&gt;Nginx의 필요성&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;396&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bblKS2/btsDxeZ4vAU/06PNAhIFE1RKVb4cGf0BV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bblKS2/btsDxeZ4vAU/06PNAhIFE1RKVb4cGf0BV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bblKS2/btsDxeZ4vAU/06PNAhIFE1RKVb4cGf0BV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbblKS2%2FbtsDxeZ4vAU%2F06PNAhIFE1RKVb4cGf0BV0%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;975&quot; height=&quot;396&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;396&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;429&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dKnstu/btsDqhqrrLG/cgpqa56VRLvAJSXnVwS1Bk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dKnstu/btsDqhqrrLG/cgpqa56VRLvAJSXnVwS1Bk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dKnstu/btsDqhqrrLG/cgpqa56VRLvAJSXnVwS1Bk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdKnstu%2FbtsDqhqrrLG%2Fcgpqa56VRLvAJSXnVwS1Bk%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;764&quot; height=&quot;429&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;429&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Q. 개발환경 서버와 운영환경 서버가 달라야 하는 이유&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;575&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dkZIyv/btsDqiJHqpe/NS0DD8Sz58UDDm8C2KrI2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dkZIyv/btsDqiJHqpe/NS0DD8Sz58UDDm8C2KrI2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dkZIyv/btsDqiJHqpe/NS0DD8Sz58UDDm8C2KrI2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdkZIyv%2FbtsDqiJHqpe%2FNS0DD8Sz58UDDm8C2KrI2K%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;935&quot; height=&quot;575&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;575&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;760&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개발에서 사용하는 서버(Dockerfile.dev)&lt;/h2&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;644&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;231&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkRsvL/btsDqOavNFb/LWPSfx2VhryVr8RUfwVRYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkRsvL/btsDqOavNFb/LWPSfx2VhryVr8RUfwVRYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkRsvL/btsDqOavNFb/LWPSfx2VhryVr8RUfwVRYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkRsvL%2FbtsDqOavNFb%2FLWPSfx2VhryVr8RUfwVRYK%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;644&quot; height=&quot;231&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;231&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;소스 변경시 자동으로 전체 앱을 다시 빌드해서 변경 소스를 반영 &amp;rarr; 개발환경에 특화&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;운영환경 서버(Dockerfile)&lt;/h2&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;760&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;839&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzD4qd/btsDqkgqm6V/LaVQ0QoG99KEkJKVTlnGwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzD4qd/btsDqkgqm6V/LaVQ0QoG99KEkJKVTlnGwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzD4qd/btsDqkgqm6V/LaVQ0QoG99KEkJKVTlnGwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzD4qd%2FbtsDqkgqm6V%2FLaVQ0QoG99KEkJKVTlnGwk%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;839&quot; height=&quot;428&quot; data-origin-width=&quot;839&quot; data-origin-height=&quot;428&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;소스 변경시 변경 소스 반영X &amp;rarr;개발에 필요한 기능들이 필요하지 않아 더 깔끔함&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;Nginx의 장점&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Q. Docker에서 nginx를 사용하는 이유는?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nginx(리버스 프록시 서버)는 백엔드 서버 앞에 위치해서 클라이언트 요청을 백엔드 서버로 전달&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로인해 아래와 같은 장점이 있음&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;백엔드 서버의 주소 숨길 수 있음(리버스 프록시)&lt;/li&gt;
&lt;li&gt;들어오는 네트워크 트래픽을 여러 서버에 분산시켜 부하를 균등하게 분배(로드 밸런싱)&lt;/li&gt;
&lt;li&gt;자주 요청되는 데이터(예: 이미지, CSS, JavaScript 파일 등)를 캐시에 저장 &amp;rarr; 서버 응답시간 단축&lt;/li&gt;
&lt;li&gt;SSL(웹사이트-사용자간 통신 암호화, 보안유지 프로토콜) 처리로 안전한 HTTPS 연결 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Nginx을 Compose에 적용&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. dockerfile.nginx 파일 생성 및 적용(dockerfile-folder/web/dockerfile.nginx)&lt;/h2&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;FROM nginx:latest
COPY ./default.conf /etc/nginx/conf.d/default.conf
EXPOSE 80&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. default.conf 파일 생성 및 작성(dockerfile-folder/web/default.conf)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;default.conf&lt;/span&gt; 파일이 &lt;span&gt;Dockerfile.nginx&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;default.conf 와 nginx.conf
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;nginx.conf
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;nginx.conf는 Nginx의 전역 설정(worker 프로세스의 수, 로그파일의 위치, 클라이언트 요청 방법) 을 정의&lt;/li&gt;
&lt;li&gt;but 일반적으로 Docker를 사용할 때는 Docker Hub에서 제공하는 Nginx 이미지를 가져와서 사용하고, 이 이미지에는 기본 &lt;span&gt;nginx.conf&lt;/span&gt; 파일이 이미 포함되어 있어 이걸 사용함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;default.conf
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 서버 또는 도메인에 대한 설정을 정의(어떤 포트에서 리스닝할껀지, SSL설정, 리버스 프록시 설정)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;server {
    listen 80;
    server_name localhost;

    location / {
        proxy_pass http://web:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3.  docker-compose.yaml 추가 (dockerfile-folder/docker-compose.yaml)&lt;/h2&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;services:
  web:
    build:
      context: ./web
      dockerfile: Dockerfile
    ports:
      - &quot;5000:5000&quot;
    depends_on:
      - db
    environment:
      DATABASE_USER: ${MYSQL_USER}
      DATABASE_PASSWORD: ${MYSQL_PASSWORD}
      DATABASE_NAME: ${MYSQL_DATABASE}
    networks:
      - backend


  nginx:
    build:
      context: ./web
      dockerfile: dockerfile.nginx
    networks:
      - backend
    ports:
      - &quot;80:80&quot;
    depends_on:
      - db&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4.  docker build&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;docker-compose down
docker-compose up --build
[+] Building 1.1s (17/17) FINISHED                                                                                 docker:desktop-linux
 =&amp;gt; [web internal] load build definition from dockerfile                                                                           0.0s
 =&amp;gt; =&amp;gt; transferring dockerfile: 837B                                                                                               0.0s
 =&amp;gt; [web internal] load .dockerignore                                                                                              0.0s
 =&amp;gt; =&amp;gt; transferring context: 2B                                                                                                    0.0s
 =&amp;gt; [web internal] load metadata for docker.io/library/python:3.8-slim                                                             1.0s
 =&amp;gt; [nginx internal] load .dockerignore                                                                                            0.0s
 =&amp;gt; =&amp;gt; transferring context: 2B                                                                                                    0.0s
 =&amp;gt; [nginx internal] load build definition from dockerfile.nginx                                                                   0.0s
 =&amp;gt; =&amp;gt; transferring dockerfile: 159B                                                                                               0.0s
 =&amp;gt; [nginx internal] load metadata for docker.io/library/nginx:latest                                                              0.0s
 =&amp;gt; [nginx internal] load build context                                                                                            0.0s
 =&amp;gt; =&amp;gt; transferring context: 398B                                                                                                  0.0s
 =&amp;gt; CACHED [nginx 1/2] FROM docker.io/library/nginx:latest                                                                         0.0s
 =&amp;gt; [nginx 2/2] COPY ./default.conf /etc/nginx/conf.d/default.conf                                                                 0.0s
 =&amp;gt; [nginx] exporting to image                                                                                                     0.0s
 =&amp;gt; =&amp;gt; exporting layers                                                                                                            0.0s
 =&amp;gt; =&amp;gt; writing image     0.0s
 =&amp;gt; =&amp;gt; naming to docker.io/library/dockerfile-folder-nginx                                                                         0.0s
 =&amp;gt; [web 1/5] FROM docker.io/library/python:3.8-slim@s     0.0s
 =&amp;gt; [web internal] load build context                                                                                              0.0s
 =&amp;gt; =&amp;gt; transferring context: 2.03kB                                                                                                0.0s
 =&amp;gt; CACHED [web 2/5] WORKDIR /app                                                                                                  0.0s
 =&amp;gt; CACHED [web 3/5] COPY requirements.txt .                                                                                       0.0s
 =&amp;gt; CACHED [web 4/5] RUN pip install --no-cache-dir -r requirements.txt                                                            0.0s
 =&amp;gt; [web 5/5] COPY . .                                                                                                             0.0s
 =&amp;gt; [web] exporting to image                                                                                                       0.0s
 =&amp;gt; =&amp;gt; exporting layers                                                                                                            0.0s
 =&amp;gt; =&amp;gt; writing image                                     0.0s
 =&amp;gt; =&amp;gt; naming to docker.io/library/dockerfile-folder-web                                                                           0.0s
[+] Running 5/3
 ✔ Network dockerfile-folder_backend    Created                                                                                    0.0s 
 ✔ Network dockerfile-folder_default    Created                                                                                    0.0s 
 ✔ Container mysql-container-web        Created                                                                                    0.1s 
 ✔ Container dockerfile-folder-nginx-1  Created                                                                                    0.0s 
 ✔ Container dockerfile-folder-web-1    Created                                                                                    0.1s 
Attaching to dockerfile-folder-nginx-1, dockerfile-folder-web-1, mysql-container-web

docker-compose logs nginx #에러가 있을 경우&lt;/code&gt;&lt;/pre&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;575&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;575&quot; data-origin-height=&quot;301&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uf8Rr/btsDwFwHDoX/hYwpD3HrDdnQgHmAch4Ax1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uf8Rr/btsDwFwHDoX/hYwpD3HrDdnQgHmAch4Ax1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uf8Rr/btsDwFwHDoX/hYwpD3HrDdnQgHmAch4Ax1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fuf8Rr%2FbtsDwFwHDoX%2FhYwpD3HrDdnQgHmAch4Ax1%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;575&quot; height=&quot;301&quot; data-origin-width=&quot;575&quot; data-origin-height=&quot;301&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;575&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&amp;nbsp;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/&quot;&gt;https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://newwisdom.tistory.com/105&quot;&gt;https://newwisdom.tistory.com/105&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@rajani103/deploying-a-noteapp-project-by-nginx-920067dca1b5&quot;&gt;https://medium.com/@rajani103/deploying-a-noteapp-project-by-nginx-920067dca1b5&lt;/a&gt;&lt;/p&gt;</description>
      <category>DOCKER</category>
      <author>PeonyF</author>
      <guid isPermaLink="true">https://peonyf.tistory.com/208</guid>
      <comments>https://peonyf.tistory.com/entry/DOCKER-Docker-compose%EC%97%90-nginx-%EC%A0%81%EC%9A%A9%EA%B8%B0#entry208comment</comments>
      <pubDate>Mon, 15 Jan 2024 20:09:19 +0900</pubDate>
    </item>
    <item>
      <title>[DOCKER] Docker Compose</title>
      <link>https://peonyf.tistory.com/entry/DOCKER-Docker-Compose</link>
      <description>&lt;h1 data-pm-slice=&quot;1 3 []&quot;&gt;Docker Compose&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 서버에서 여러개의 컨테이너를 하나의 서비스로 정의해 컨테이너의 묶음으로 관리할 수 있는 작업 환경을 제공하는 관리 도구&lt;/p&gt;
&lt;h1&gt;Docker Compose 사용 이유&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 개의 컨테이너가 하나의 어플리케이션으로 동작시, 도커 컴포즈를 사용하지 않는다면, 이를 테스트하기 위해 각 컨테이너를 하나씩 생성해야 하기때문&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex. web application test = web server container,db container 각각 생성&lt;/p&gt;
&lt;h1&gt;Docker Compose 특징&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;run 명령어의 옵션을 그대로 사용 가능&lt;/li&gt;
&lt;li&gt;각 컨테이너의 의존성,네트워크,볼륨등을 함께 정의 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Docker Compose 작성 방법&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Compose에서는 YAML파일을 사용하여 application 서비스를 구성(명세)함&lt;/li&gt;
&lt;li&gt;Compose 파일의 기본 양식은 &lt;span&gt;compose.yaml&lt;/span&gt; 혹은 &lt;span&gt;compose.yml&lt;/span&gt; 이다.&lt;/li&gt;
&lt;li&gt;Compose는 다음과 같이 3단계 프로세스로 진행됨
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span&gt;Dockerfile&lt;/span&gt;에 애플리케이션을 작성. &amp;rarr; 어디서나 재현가능한 환경을 제공&lt;/li&gt;
&lt;li&gt;application 서비스들을 compose.yml에 정의하여 함께 실행될 수 있도록 함&lt;/li&gt;
&lt;li&gt;docker compose up을 통해 전체 앱을 실행&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Docker Compose 구조&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1489&quot; data-origin-height=&quot;531&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccvaSk/btsDpcby453/8MI6ObTdboU52koo53J9wk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccvaSk/btsDpcby453/8MI6ObTdboU52koo53J9wk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccvaSk/btsDpcby453/8MI6ObTdboU52koo53J9wk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccvaSk%2FbtsDpcby453%2F8MI6ObTdboU52koo53J9wk%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;1489&quot; height=&quot;531&quot; data-origin-width=&quot;1489&quot; data-origin-height=&quot;531&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Version : 지원 버전 확인&lt;/li&gt;
&lt;li&gt;Service : 도커 컴포즈로 생성할 각 컨테이너의 옵션을 정의&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1704698851504&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: '3'
services:
  web:
    build: . # build 항목에 정의된 도커파일에서 이미지를 빌드해 서비스의 컨테이너를 생성하도록 설정(현재 디렉토리일 경우 .)
    command: npm start # 컨테이너가 시작될 때 실행될 명령어를 지정
    ports: #서비스의 컨테이너를 개방할 포트 설정
      - &quot;8080:80&quot;
    depends_on: # 이 서비스가 의존하는 다른 서비스를 지정
      - db
    links: # 다른 서비스에 서비스명만으로 접근할 수 있도록 설정
      - db:database
    extends: # 다른 yaml 파일이나 현재 yaml 파일에서 서비스 속성을 상속 받도록 설정
      file: common-services.yml # 다른 파일에서 서비스 정의를 상속받음
      service: webbase

  db:
    image: mysql
    ports:
      - &quot;3306:3306&quot;
    environment: # 서비스의 컨테이너 내부에서 사용할 환경변수를 지정, 딕셔너리나 배열 형태로 사용할 수 있음 
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_USER=user
      - MYSQL_PASSWORD=password
      - MYSQL_DATABASE=demodb
    command: --default-authentication-plugin=mysql_native_password # 데이터베이스를 시작할 때 사용할 명령어 옵션을 지정&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-pm-slice=&quot;3 1 []&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Network : Service는 Network를 통해 서로 통신&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-mode=&quot;wide&quot;&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;networks:
  mynetwork:
    driver: overlay
    driver_opts:
      subnet: &quot;255.255.255.0&quot;  # 스웜 모드나 주키퍼를 사용하는 환경이어야만 생성(일반적으로 overlay에선 사용x)
    ipam:
      driver: default  # 'mydriver'는 예시이며, 실제 사용 가능한 IPAM 드라이버를 지정해야 합니다.
      config:
        - subnet: &quot;172.20.0.0/16&quot;
          ip_range: &quot;172.20.5.0/24&quot;
          gateway: &quot;172.20.5.1&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Volume : 서비스는 영구적으로 유지해야 할 데이터를 Volume에 저장하고 공유함&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-mode=&quot;wide&quot;&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;volumes:
  myvolume:
    driver: local  # 'flocker'는 예시이며, 실제 사용할 볼륨 드라이버를 지정해야 합니다.
    driver_opts:
      type: &quot;nfs&quot;  # 이것은 NFS 볼륨을 예로 든 것이며, 사용할 볼륨의 실제 옵션에 따라 달라질 수 있음
      o: &quot;addr=192.168.1.1,rw&quot;
      device: &quot;:/path/to/dir&quot;
    external: true  #원래 프로젝트마다 volumes을 생성, 이때 external 옵션 설정시 기존 volumes을 사용함&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 data-pm-slice=&quot;1 1 []&quot;&gt;실제 연습&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1.mysql 설치 및 기본 설정&lt;/h2&gt;
&lt;div data-level=&quot;1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 datagrip을 써도 mysql에 들어가서 user등록을 해줘야한다.. &lt;s&gt;datagrip에서 될줄알고 한참을 했지만 실패했다..&lt;/s&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://study-ce.tistory.com/54&quot;&gt;https://study-ce.tistory.com/54&lt;/a&gt; 참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;background-color: #f7f7f7; border: #c1c1c1 1px solid; padding: 10px;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-panel-content=&quot;true&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.apt update : sudo apt update&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.mysql 설치 : sudo apt install mysql-server (&lt;b&gt;brew install mysql &amp;rarr; brew services start mysql&lt;/b&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.mysql 이름/password 설정&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3-1. sudo mysql -u root -p&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3-2. use mysql;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3-3. CREATE USER '{생성할 사용자 이름}'@'%' IDENTIFIED BY '{비밀번호}';&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3-4. GRANT ALL PRIVILEGES ON *.* TO '{사용자 이름}'@'%';&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3-5. FLUSH PRIVILEGES;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3-6. exit&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;sudo mysql -u root -p&lt;br /&gt;use mysql;&lt;br /&gt;CREATE USER '{생성할 사용자 이름}'@'%' IDENTIFIED BY '{비밀번호}';&lt;br /&gt;GRANT ALL PRIVILEGES ON&amp;nbsp;.&amp;nbsp;TO '{사용자 이름}'@'%';&lt;br /&gt;FLUSH PRIVILEGES;&lt;br /&gt;exit;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4.mysql 설정 파일 수정(외부 접속 허용)&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4-1. brew info mysql &amp;rarr; ls /usr/local/etc/my.cnf or ls /usr/local/etc/my.cnf.d/sudo nano &amp;rarr; /usr/local/etc/my.cnf&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4-2. bind-address = 0.0.0.0 으로 수정(외부접속 허용)&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4-3. sudo service mysql restart (or brew services restart mysql)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5.datagrip 연동&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;2.mysql table 작성&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;CREATE DATABASE IF NOT EXISTS dockerdb;
USE dockerdb;

CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    email VARCHAR(50) NOT NULL
);

INSERT INTO users (username, email) VALUES ('chacha', 'chacha@example.com');
INSERT INTO users (username, email) VALUES ('chacha_test', 'chacha_test@example.com')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;109&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bC6yBu/btsC52fYzFG/JYoAj0MQZH6K2OtEsKXkZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bC6yBu/btsC52fYzFG/JYoAj0MQZH6K2OtEsKXkZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bC6yBu/btsC52fYzFG/JYoAj0MQZH6K2OtEsKXkZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbC6yBu%2FbtsC52fYzFG%2FJYoAj0MQZH6K2OtEsKXkZ1%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;714&quot; height=&quot;109&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;109&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;714&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;
&lt;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;3.docker-compose.yaml과 dockerfile 작성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/dockerfile-folder/web/app.py&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;import pymysql
from flask import Flask, jsonify

app = Flask(__name__)


def get_db_connection():
    return pymysql.connect(host='host.docker.internal',
                           user='docker_chacha',
                           password='1q2w3e4r',
                           db='dockerdb',
                           charset='utf8mb4')


@app.route('/')
def hello_world():
    return 'Hello World!'


@app.route('/users')
def list_users():
    connection = get_db_connection()
    cursor = connection.cursor(pymysql.cursors.DictCursor)
    cursor.execute(&quot;SELECT * FROM users&quot;)
    users = cursor.fetchall()
    cursor.close()
    connection.close()
    return jsonify(users)


if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/dockerfile-folder/web/requirements.txt&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;FLASK==3.0.0
# MYSQL==0.0.3
PyMySQL==0.10.1
cryptography&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/dockerfile-folder/web/dockerfile&lt;/p&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;FROM python:3.8-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
ENV NAME dockertest
CMD [&quot;python&quot;, &quot;app.py&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dockerfile-folder/docker-compose.yaml&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*도커 컴포즈의 파일 이름은 꼭 docker-compose로 해줘야 한다.&lt;/p&gt;
&lt;pre class=&quot;http&quot;&gt;&lt;code&gt;version: '3.8'

services:
  web:
    build: ./web
    ports:
      - &quot;5000:5000&quot;
    depends_on:
      - db
    environment:
      DATABASE_USER: ${MYSQL_USER}
      DATABASE_PASSWORD: ${MYSQL_PASSWORD}
      DATABASE_NAME: ${MYSQL_DATABASE}
    networks:
      - backend

  db:
    image: mysql:8.2
    container_name: mysql-container-web
    environment:
      MYSQL_ROOT_HOST: ${MYSQL_ROOT_HOST}
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
    ports:
      - &quot;3306:3306&quot;
    command: # 명령어 실행
      - &quot;mysqld&quot;
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
    volumes:
      - ./mysql/conf.d:/etc/mysql/conf.d # MySQL 설정 파일 위치
      - ./mysql/initdb.d/:/docker-entrypoint-initdb.d/  # 데이터베이스 초기화 sql

networks:
  backend:
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/dockerfile-folder/.env&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;MYSQL_ROOT_HOST=localhost
MYSQL_ROOT_PASSWORD=
MYSQL_USER=docker_chacha
MYSQL_PASSWORD=
MYSQL_DATABASE=dockerdb&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 실행시켜서 확인한다.&lt;/h2&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;docker-compose build
docker-compose up -d # Background로 도커 컴포즈 프로젝트 실행

#파일 수정 시
docker-compose down # 프로젝트 내 컨테이너 및 네트워크 종료 및 제거
docker-compose build --no-cache
docker-compose up        &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;% docker-compose build           
[+] Building 3.0s (11/11) FINISHED                                                                                 docker:desktop-linux
 =&amp;gt; [web internal] load .dockerignore                                                                                              0.0s
 =&amp;gt; =&amp;gt; transferring context: 2B                                                                                                    0.0s
 =&amp;gt; [web internal] load build definition from dockerfile                                                                           0.0s
 =&amp;gt; =&amp;gt; transferring dockerfile: 837B                                                                                               0.0s
 =&amp;gt; [web internal] load metadata for http://docker.io/library/python:3.8-slim                                                              2.8s
 =&amp;gt; [web auth] library/python:pull token for registry-1.docker.io                                                                  0.0s
 =&amp;gt; [web 1/5] FROM http://docker.io/library/python:3.8-slim@sha256:d1cba0f8754d097bd333b8f3d4c655f37c2ede9042d1e7db69561d9eae2eebfa        0.0s
 =&amp;gt; [web internal] load build context                                                                                              0.0s
 =&amp;gt; =&amp;gt; transferring context: 1.80kB                                                                                                0.0s
 =&amp;gt; CACHED [web 2/5] WORKDIR /app                                                                                                  0.0s
 =&amp;gt; CACHED [web 3/5] COPY requirements.txt .                                                                                       0.0s
 =&amp;gt; CACHED [web 4/5] RUN pip install --no-cache-dir -r requirements.txt                                                            0.0s
 =&amp;gt; [web 5/5] COPY . .                                                                                                             0.0s
 =&amp;gt; [web] exporting to image                                                                                                       0.0s
 =&amp;gt; =&amp;gt; exporting layers                                                                                                            0.0s
 =&amp;gt; =&amp;gt; writing image sha256:4012d3f308eda6190aa7e5796bdf1d42ea7d18f16391bf9c62f5db8e2cdb13c6                                       0.0s
 =&amp;gt; =&amp;gt; naming to http://docker.io/library/dockerfile-folder-web                                                                            0.0s
% docker-compose up -d
[+] Building 0.0s (0/0)                                                                                            docker:desktop-linux
[+] Running 2/2
 ✔ Container mysql-container-web      Running                                                                                      0.0s
 ✔ Container dockerfile-folder-web-1  Started                                                                                      0.6s
(base) choimijung@choemijeong-ui-noteubug ~/Desktop/dockerfile-folder %&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹사이트에서 확인&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;131&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RthLW/btsC54LEkgc/MsXVz3T7tWUjrE8sKpPs5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RthLW/btsC54LEkgc/MsXVz3T7tWUjrE8sKpPs5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RthLW/btsC54LEkgc/MsXVz3T7tWUjrE8sKpPs5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRthLW%2FbtsC54LEkgc%2FMsXVz3T7tWUjrE8sKpPs5K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;506&quot; height=&quot;131&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;131&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;304&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddm5oW/btsC9m5AkaC/kx2tcEcYWkhKXDmfF8hVm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddm5oW/btsC9m5AkaC/kx2tcEcYWkhKXDmfF8hVm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddm5oW/btsC9m5AkaC/kx2tcEcYWkhKXDmfF8hVm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fddm5oW%2FbtsC9m5AkaC%2Fkx2tcEcYWkhKXDmfF8hVm1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;506&quot; height=&quot;304&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;304&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-pm-slice=&quot;1 2 []&quot; data-ke-size=&quot;size26&quot;&gt;발생했던 문제상황&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제1. unable to prepare context: path &quot;/dockerfile-folder/web&quot; not found&lt;/h4&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBouq3/btsC8Vf5exX/mDAKXBqxJTctpXGn3dufI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBouq3/btsC8Vf5exX/mDAKXBqxJTctpXGn3dufI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBouq3/btsC8Vf5exX/mDAKXBqxJTctpXGn3dufI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBouq3%2FbtsC8Vf5exX%2FmDAKXBqxJTctpXGn3dufI1%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;714&quot; height=&quot;164&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;164&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1026&quot; data-origin-height=&quot;164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcgx9S/btsC7qm5hmV/nEbQNY6klFpCfVVzATFkK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcgx9S/btsC7qm5hmV/nEbQNY6klFpCfVVzATFkK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcgx9S/btsC7qm5hmV/nEbQNY6klFpCfVVzATFkK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbcgx9S%2FbtsC7qm5hmV%2FnEbQNY6klFpCfVVzATFkK1%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;1026&quot; height=&quot;164&quot; data-origin-width=&quot;1026&quot; data-origin-height=&quot;164&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div data-level=&quot;1&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;&amp;rarr; Docker Compose는 &lt;span&gt;./web&lt;/span&gt; 디렉토리에서 Dockerfile을 찾으려고 시도하지만 해당 디렉토리가 존재하지 않아 실패 아래와 같이 디렉토리 변경&lt;/p&gt;
&lt;/div&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;/dockerfile-folder/
├── web/
│   ├── Dockerfile
│   ├── app.py
│   ├── requirements.txt
│   └── ... (기타 필요한 파일들)
└── docker-compose.yml&lt;/code&gt;&lt;/pre&gt;
&lt;div data-level=&quot;1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발생 이유 : docker-compose.yaml 파일이 아래와 같이 build가 ./web에서 진행되기 때문&lt;/p&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;/div&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;467&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제2 . local mysql에 있지만 docker mysql에는 값이 없었다.(pymysql.err.ProgrammingError: (1146, &quot;Table 'dockerdb.users' doesn't exist&quot;))&lt;/h4&gt;
&lt;div data-level=&quot;1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; docker-compose.yaml에 아래와 같이 추가&lt;/p&gt;
&lt;/div&gt;
&lt;pre class=&quot;haml&quot;&gt;&lt;code&gt;    command: # 명령어 실행
      - &quot;mysqld&quot;
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
    volumes:
      - ./mysql/conf.d:/etc/mysql/conf.d # MySQL 설정 파일 위치
      - ./mysql/initdb.d/:/docker-entrypoint-initdb.d/  # 데이터베이스 초기화 sql&lt;/code&gt;&lt;/pre&gt;
&lt;div data-level=&quot;1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; app.py의 host에 db대신 &lt;span&gt;'host.docker.internal'&lt;/span&gt; 로 값 변경&lt;/p&gt;
&lt;/div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;def get_db_connection():
#기존 코드
    return pymysql.connect(host='db',
#바뀐 코드
    return pymysql.connect(host='host.docker.internal',
                           user='docker_chacha',
                           password='',
                           db='dockerdb',
                           charset='utf8mb4')
&lt;/code&gt;&lt;/pre&gt;
&lt;div data-level=&quot;1&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;발생 이유&amp;nbsp;&lt;/h4&gt;
&lt;/div&gt;
&lt;div data-panel-type=&quot;note&quot;&gt;
&lt;div data-panel-content=&quot;true&quot;&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;background-color: #f7f7f7; border: #c1c1c1 1px solid; padding: 10px;&quot;&gt;
&lt;div data-panel-content=&quot;true&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;volume 추가:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hostsystem-container간의 디렉토리 공유를 위해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;./mysql/conf.d:/etc/mysql/conf.d&lt;/span&gt;: MySQL 설정 파일을 Docker 컨테이너와 공유&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;--character-set-server=utf8mb4&lt;/span&gt;: 문자 인코딩을 &lt;span&gt;utf8mb4&lt;/span&gt;로 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;./mysql/initdb.d/:/docker-entrypoint-initdb.d/&lt;/span&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; MySQL 인스턴스가 처음 시작될 때 실행할 SQL 파일이나 스크립트를 담고 있  필요한 데이터베이스, 테이블, 기본 데이터 등을 자동으로 설정(&lt;span&gt;users&lt;/span&gt; 테이블을 생성하는 SQL 파일 포함)&lt;/p&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;'host.docker.internal'로 변경&lt;/b&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'db'라는 호스트 이름은 일반적으로 Docker 네트워크 내에서 다른 컨테이너를 가리킬 때 사용(&lt;s&gt;이것 때문에 엄청 고생했다..)&lt;/s&gt; 따라서 &lt;span&gt;db&lt;/span&gt;라는 이름으로 연결하려고 시도하면 실제 데이터베이스 호스트를 찾을 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;host.docker.internal&lt;/span&gt; : 애플리케이션이 Docker 내부에서 실행되고 있더라도, 이 설정을 통해 Docker 외부에 있는 MySQL 서버에 접근 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜?&amp;nbsp;docker container 내부에서 localhost는 container 자신을 의미함(lockerhost = docker conainer 내부)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;문제2 발생시 확인 방법&lt;/h4&gt;
&lt;div data-level=&quot;1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;span&gt;docker-compose ps &lt;/span&gt;사용해서 제대로 돌아가고 있는지 확인&lt;/p&gt;
&lt;/div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;% docker-compose ps  # 도커 컴포즈 프로젝트 목록 확인
NAME                     IMAGE       COMMAND                         SERVICE   CREATED          STATUS          PORTS
dockerfile-folder-db-1   mysql:8.2   &quot;docker-entrypoint.sh mysqld&quot;   db        11 minutes ago   Up 11 minutes   3306/tcp, 33060/tcp&lt;/code&gt;&lt;/pre&gt;
&lt;div data-level=&quot;1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 정확하게 어느 부분에서 에러가 나고 있는지 확인&lt;/p&gt;
&lt;/div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;% docker-compose logs web
dockerfile-folder-web-1  |  * Serving Flask app 'app'
dockerfile-folder-web-1  |  * Debug mode: on
dockerfile-folder-web-1  | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
dockerfile-folder-web-1  |  * Running on all addresses (0.0.0.0)
dockerfile-folder-web-1  |  * Running on http://127.0.0.1:5000
dockerfile-folder-web-1  |  * Running on http://172.21.0.3:5000
dockerfile-folder-web-1  | Press CTRL+C to quit
dockerfile-folder-web-1  |  * Restarting with stat
dockerfile-folder-web-1  |  * Debugger is active!
dockerfile-folder-web-1  |  * Debugger PIN: 124-494-128
dockerfile-folder-web-1  | 192.168.65.1 - - [03/Jan/2024 05:22:53] &quot;GET / HTTP/1.1&quot; 200 -
dockerfile-folder-web-1  | 192.168.65.1 - - [03/Jan/2024 05:23:00] &quot;GET /users HTTP/1.1&quot; 500 -
dockerfile-folder-web-1  | Traceback (most recent call last):
...
dockerfile-folder-web-1  |   File &quot;/app/app.py&quot;, line 24, in list_users
dockerfile-folder-web-1  |     cursor.execute(&quot;SELECT * FROM users&quot;)
dockerfile-folder-web-1  |   File &quot;/usr/local/lib/python3.8/site-packages/pymysql/cursors.py&quot;, line 163, in execute
dockerfile-folder-web-1  |     result = self._query(query)
...
dockerfile-folder-web-1  |   File &quot;/usr/local/lib/python3.8/site-packages/pymysql/protocol.py&quot;, line 223, in raise_for_error
dockerfile-folder-web-1  |     err.raise_mysql_exception(self._data)
dockerfile-folder-web-1  |   File &quot;/usr/local/lib/python3.8/site-packages/pymysql/err.py&quot;, line 107, in raise_mysql_exception
dockerfile-folder-web-1  |     raise errorclass(errno, errval)
dockerfile-folder-web-1  | pymysql.err.ProgrammingError: (1146, &quot;Table 'dockerdb.users' doesn't exist&quot;)
dockerfile-folder-web-1  | 192.168.65.1 - - [03/Jan/2024 05:23:01] &quot;GET /users?__debugger__=yes&amp;amp;cmd=resource&amp;amp;f=debugger.js HTTP/1.1&quot; 304 -&lt;/code&gt;&lt;/pre&gt;
&lt;div data-level=&quot;1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3-1.Flask 애플리케이션이 실행 중인 &lt;span&gt;dockerfile-folder-web-1&lt;/span&gt; 컨테이너의 쉘에 접속 &amp;rarr; app 코드 직접 입력&lt;/p&gt;
&lt;/div&gt;
&lt;div data-mode=&quot;wide&quot;&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;% docker compose ps
NAME                      IMAGE                   COMMAND                         SERVICE   CREATED          STATUS          PORTS
dockerfile-folder-db-1    mysql:8.2               &quot;docker-entrypoint.sh mysqld&quot;   db        11 minutes ago   Up 11 minutes   3306/tcp, 33060/tcp
dockerfile-folder-web-1   dockerfile-folder-web   &quot;python ./app.py&quot;               web       11 minutes ago   Up 11 minutes   0.0.0.0:5000-&amp;gt;5000/tcp

#ps로 Name확인 후 해당 container 접속
% docker exec -it dockerfile-folder-web-1 /bin/sh

# Python 실행
python
&amp;gt;&amp;gt;&amp;gt; import pymysql
&amp;gt;&amp;gt;&amp;gt; 
&amp;gt;&amp;gt;&amp;gt; # Use the same credentials and host as in your Flask app
&amp;gt;&amp;gt;&amp;gt; conn = pymysql.connect(
...     host='db',  # This is the service name in docker-compose
...     user='docker_chacha',  # Your database username
...     password='1111',  # Your database password
...     db='dockerdb',  # Your database name
... )
&amp;gt;&amp;gt;&amp;gt; 
&amp;gt;&amp;gt;&amp;gt; # Now, try to execute a simple query
&amp;gt;&amp;gt;&amp;gt; with conn.cursor() as cursor:
...     cursor.execute(&quot;SHOW TABLES;&quot;)
...     print(cursor.fetchall())
... 
0
()
&amp;gt;&amp;gt;&amp;gt; conn.close()

#&quot;SHOW TABLES;&quot; 쿼리를 실행한 결과 0 ()가 반환됨 -&amp;gt;   해당 데이터베이스(dockerdb)에 테이블이 없다는 것을 의미

&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3-2. Flask 애플리케이션이 실행 중인 &lt;span&gt;dockerfile-folder-web-1&lt;/span&gt; 컨테이너의 쉘에 접속-&amp;gt; mysql 접속 및 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dockerfile안에 내용 변경&lt;/p&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;FROM python:3.8-slim
WORKDIR /app
COPY requirements.txt .
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y iputils-ping \
    &amp;amp;&amp;amp; apt-get install -y --no-install-recommends default-mysql-client \
    &amp;amp;&amp;amp; apt-get clean \
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
RUN pip install -r requirements.txt
COPY . .
EXPOSE 5000
ENV NAME dockertest
CMD [&quot;python&quot;, &quot;app.py&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;docker exec -it dockerfile-folder-db-1 /bin/bash

# MySQL 클라이언트 실행
mysql -u docker_chacha -p

# 패스워드 입력: &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*참고자료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;따라하며 배우는 도커와 CI환경&lt;/b&gt; 강의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@whattsup_kim/Docker-Compose-Compose-Specification&quot;&gt;https://velog.io/@whattsup_kim/Docker-Compose-Compose-Specification&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://seosh817.tistory.com/387&quot;&gt;https://seosh817.tistory.com/387&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developerbee.tistory.com/236&quot;&gt;https://developerbee.tistory.com/236&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://shawn-dev.oopy.io/463a30bf-bf32-44e4-88be-8b4722e5549a&quot;&gt;https://shawn-dev.oopy.io/463a30bf-bf32-44e4-88be-8b4722e5549a&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/44543842/how-to-connect-locally-hosted-mysql-database-with-the-docker-container/61480668#61480668&quot;&gt;https://stackoverflow.com/questions/44543842/how-to-connect-locally-hosted-mysql-database-with-the-docker-container/61480668#61480668&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://marklee1117.tistory.com/93&quot;&gt;https://marklee1117.tistory.com/93&lt;/a&gt;&lt;/p&gt;</description>
      <category>DOCKER</category>
      <author>PeonyF</author>
      <guid isPermaLink="true">https://peonyf.tistory.com/207</guid>
      <comments>https://peonyf.tistory.com/entry/DOCKER-Docker-Compose#entry207comment</comments>
      <pubDate>Mon, 8 Jan 2024 19:36:17 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] Docker Volume</title>
      <link>https://peonyf.tistory.com/entry/Docker-Docker-Volume</link>
      <description>&lt;h1 data-pm-slice=&quot;1 1 []&quot;&gt;Docker Storage 필요성&lt;/h1&gt;
&lt;div data-pm-slice=&quot;0 0 []&quot; data-width-type=&quot;pixel&quot; data-width=&quot;618&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;373&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OQDJX/btsCKQz0aDX/5heexlGV4Gq2kMqt79jonK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OQDJX/btsCKQz0aDX/5heexlGV4Gq2kMqt79jonK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OQDJX/btsCKQz0aDX/5heexlGV4Gq2kMqt79jonK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOQDJX%2FbtsCKQz0aDX%2F5heexlGV4Gq2kMqt79jonK%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;618&quot; height=&quot;373&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dms0VK/btsCP2ze4pe/o55zQp3uu8yjmwBRIlTuKk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dms0VK/btsCP2ze4pe/o55zQp3uu8yjmwBRIlTuKk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dms0VK/btsCP2ze4pe/o55zQp3uu8yjmwBRIlTuKk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdms0VK%2FbtsCP2ze4pe%2Fo55zQp3uu8yjmwBRIlTuKk%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;733&quot; height=&quot;600&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;958&quot; data-origin-height=&quot;541&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIiXT3/btsCG13c8EL/ytdfseC76NPywHP7mx9x61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIiXT3/btsCG13c8EL/ytdfseC76NPywHP7mx9x61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIiXT3/btsCG13c8EL/ytdfseC76NPywHP7mx9x61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIiXT3%2FbtsCG13c8EL%2FytdfseC76NPywHP7mx9x61%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;958&quot; height=&quot;541&quot; data-origin-width=&quot;958&quot; data-origin-height=&quot;541&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-pm-slice=&quot;1 3 []&quot; data-ke-size=&quot;size26&quot;&gt;1. Docker Layer = Container Layer + Image Layer&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Image Layer = Read Only : Docker Image는 읽기전용이며 어떠한 경우에도 변경되지 않음(변경사항 적용X)&lt;/li&gt;
&lt;li&gt;Container Layer = Writable&lt;/li&gt;
&lt;li&gt;Writable Layer : 컨테이너가 생성될때, Dockers는 읽기 전용 이미지 위에 &amp;ldquo;Writable Layer&amp;rdquo;를 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-level=&quot;1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 이 레이어에서 컨테이너 내의 변경사항(파일 추가,수정,삭제 등)이 처리됨&lt;/p&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Writable Layer의 휘발성 : Container 삭제시 Writable Layer에 저장된 모든 데이터도 함께 삭제됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Container의 Data 저장 문제점(휘발성)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Container의 Writable Layer에 Data를 저장할 수 있지만 몇가지 문제점이 있음&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Container 삭제시 Data 삭제 &amp;rarr; 다른 Process에서 Container에 저장된 Data를 사용X&lt;/li&gt;
&lt;li&gt;이미지를 통해 Container를 만들면 Container는 읽기 전용이 되고 컨테이너 변경사항만 별도로 저장하여 컨테이너 정보를 보존한다. 이때 이미지는 어떠한 경우로도 변경되지 않는다.&lt;/li&gt;
&lt;li&gt;Container의 Writable Layer가 실행중인 host system과 밀접하게 연결 (Writable Layer가 실행 중인  host storage system에 저장되어 관리되기 때문) + Container의 생명주기와 연결되어있어 = 데이터를 다른곳으로 옮기기 힘듦(데이터를 다른 시스템으로 이전시 변환과정 필요 및, 데이터가 지속적으로 있단 보장이 없음)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 data-pm-slice=&quot;1 1 []&quot;&gt;Docker Storage&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1257&quot; data-origin-height=&quot;618&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biS1xh/btsCIHJ9Lkz/6HRJuFltTRMZqrfkDajlr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biS1xh/btsCIHJ9Lkz/6HRJuFltTRMZqrfkDajlr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biS1xh/btsCIHJ9Lkz/6HRJuFltTRMZqrfkDajlr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiS1xh%2FbtsCIHJ9Lkz%2F6HRJuFltTRMZqrfkDajlr0%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;1257&quot; height=&quot;618&quot; data-origin-width=&quot;1257&quot; data-origin-height=&quot;618&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1029&quot; data-origin-height=&quot;289&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMk2Hp/btsCUySTcRo/e30XYq8FHsX1WbmJwL7zO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMk2Hp/btsCUySTcRo/e30XYq8FHsX1WbmJwL7zO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMk2Hp/btsCUySTcRo/e30XYq8FHsX1WbmJwL7zO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMk2Hp%2FbtsCUySTcRo%2Fe30XYq8FHsX1WbmJwL7zO0%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;1029&quot; height=&quot;289&quot; data-origin-width=&quot;1029&quot; data-origin-height=&quot;289&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;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt; Docker Volume&lt;/li&gt;
&lt;li&gt;Bind Mounts&lt;/li&gt;
&lt;li&gt;tmpfs Mounts&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Docker Volume&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1168&quot; data-origin-height=&quot;743&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvqDjA/btsCMqAUhh8/uPc7NAcycZWlyTPV2k2el1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvqDjA/btsCMqAUhh8/uPc7NAcycZWlyTPV2k2el1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvqDjA/btsCMqAUhh8/uPc7NAcycZWlyTPV2k2el1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvqDjA%2FbtsCMqAUhh8%2FuPc7NAcycZWlyTPV2k2el1%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;1168&quot; height=&quot;743&quot; data-origin-width=&quot;1168&quot; data-origin-height=&quot;743&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-pm-slice=&quot;3 1 []&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker가 제공하는 불륨 관리 기능을 통해서 볼륨을 생성하고 삭제,관리를 할 수 있다.&lt;/li&gt;
&lt;li&gt;Volume이란 Host file system에 저장되는 디렉터리나 파일로, Container의 Union 파일 시스템 외부에 존재&lt;/li&gt;
&lt;li&gt;Linux 시스템에서 볼륨은 일반적으로 &lt;span&gt;/var/lib/docker/volumes/&lt;/span&gt; 디렉터리 아래에 저장되어 Docker는 이 Volume을 관리하고 Volume에 저장된 데이터는 &lt;b&gt;Host file system&lt;/b&gt;의 일부로 존재함&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-panel-type=&quot;note&quot;&gt;
&lt;div data-panel-content=&quot;true&quot;&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;background-color: #f7f7f7; border: #c1c1c1 1px solid; padding: 10px;&quot;&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Host file system 이란?&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker가 실행되고 있는 컴퓨터의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;파일 시스템&lt;/u&gt;(OS가 파일을 저장하고 관리하는 방식: 파일 저장,삭제,수정)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;즉, Docker 환경에서 호스트 파일 시스템은 Docker의 컨테이너, 이미지, 그리고 볼륨을 저장하는 기반&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;호스트 파일 시스템
│
├── Docker 이미지 (읽기 전용 레이어) : 호스트 파일 시스템에 저장되며 컨테이너를 시작시 사용
│
├── Docker 컨테이너
│   ├── 읽기 전용 레이어 (이미지에서 가져옴)
│   └── 쓰기 가능 레이어 (컨테이너 레이어): 컨테이너 실행시 '읽기 전용 레이어'위에 '쓰기 가능 레이어'를 추가
└── Volumes
    └── 영구적 데이터 저장: 컨테이너에 마운트되어 데이터를 보관 &lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Volume은 Container의 데이터를 영속적으로 저장하고 Container 사이에 데이터를 공유하기 위해 사용, Container가 삭제되어도 Volume에 저장된 데이터는 유지됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;Docker Volume VS COPY&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Volume : 로컬머신(&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;Docker가 설치되고 실행되는 기본 시스템)&lt;/span&gt;에 있는것을 맵핑(참조)해서 도커 컨테이너에서 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;개발때 소스 변경시 다시 이미지를 빌드하지 않고 변경한 소스부분이 application에 적용하도록 하기 위해&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;Copy: 로컬머신에 있는 파일을 도커 컨테이너에 복사&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rLKQS/btsDfPMKHwy/y5Faw298LKCVO1GoxeYo2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rLKQS/btsDfPMKHwy/y5Faw298LKCVO1GoxeYo2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rLKQS/btsDfPMKHwy/y5Faw298LKCVO1GoxeYo2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrLKQS%2FbtsDfPMKHwy%2Fy5Faw298LKCVO1GoxeYo2K%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;859&quot; height=&quot;416&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;416&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;415&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IyCXw/btsC8UPfaOK/2hHmKXmCkgDIYlV3KJaiv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IyCXw/btsC8UPfaOK/2hHmKXmCkgDIYlV3KJaiv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IyCXw/btsC8UPfaOK/2hHmKXmCkgDIYlV3KJaiv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIyCXw%2FbtsC8UPfaOK%2F2hHmKXmCkgDIYlV3KJaiv0%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;850&quot; height=&quot;415&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;415&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 Volume 장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Volume은 Bind Mount보다 백업, 마이그레이션이 더 쉬움&lt;/li&gt;
&lt;li&gt;Volume은 다른 컨테이너 간에 데이터를 공유하는 데에도 사용&lt;/li&gt;
&lt;li&gt;Docker CLI 명령, Docker API를 사용해 Volume을 관리 할 수 있음&lt;/li&gt;
&lt;li&gt;Docker Desktop의 Volume은 Mac,Window host의 바인드 마운트보다 성능이 훨씬 높다.&lt;/li&gt;
&lt;li&gt;Volume은 이를 사용하는 Container크기를 늘리지 않고 Volume의 컨텐츠가 지정된 Container의 수명 주기 외부에 존재해서 Container의 Writable Layer에 데이터를 유지하는 것보다 Volume을 선택하는것이 더 나은 경우가 많다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 5 []&quot; data-ke-size=&quot;size23&quot;&gt;Docker Volume 사용 사례&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행 중인 여러 Container 간에 Data 공유가 필요한 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 Container가 동일한 volume을 읽기/쓰기 또는 읽기 전용으로 동시에 Mount할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Docker Host가 특정 디렉토리나 파일 구조를 가질 수 없는 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;volume&lt;/span&gt;은 Container Runtime으로부터 Docker Host의 설정을 분리할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;로컬외의 원격 Host 및 Cloud Provider에 Container의 Data를 저장하려는 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;A Docker Host &amp;rarr; B Docker Host로 백업,복구,migration시 volume을 사용하는게 좋다.&lt;/li&gt;
&lt;li&gt;&lt;span&gt;volume&lt;/span&gt;을 사용하여 Container를 중지한 다음 &lt;span&gt;volume&lt;/span&gt;의 디렉토리(예: &lt;span&gt;/var/lib/docker/volume/&amp;lt;volume-name&amp;gt;&lt;/span&gt;)를 백업할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Docker Volume 코드&lt;/h3&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;% docker volume create testvolume
testvolume

# nginx를 testvolume에 영구 설치함, -d는 백그라운드에서 실행하란 명령어
# -v testvolume:/app/data는 testvolume : 볼륨을 컨테이너의 /app/data 디렉토리에 마운트하라고 명령
% docker run -d -v testvolume:/app/data --name mycontainer nginx

Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
24e221e92a36: Pull complete 
58cc89079bd7: Pull complete 
3799b53049f3: Pull complete 
2a580edba2f4: Pull complete 
cfe7877ea167: Pull complete 
6f26751fc54b: Pull complete 
c98494bb3682: Pull complete 
Digest: sha256:2bdc49f2f8ae8d8dc50ed00f2ee56d00385c6f8bc8a8b320d0a294d9e3b49026
Status: Downloaded newer image for nginx:latest
4d16388a956dca7f49b4059d31d84512005653fc242f3720a723e82e64b69e68

 % docker volume ls
DRIVER    VOLUME NAME
local     5f349cb6b961a651e3b2ab8395dfa011e6e6a4284cb1a8d028b9c4b213d1805d
local     23af4fea9ed9bcbdcae9fe69228324bb27714363c3ce3e31e83260793e0fef17
local     testvolume

 % docker volume inspect testvolume
[
    {
        &quot;CreatedAt&quot;: &quot;2024-01-02T05:07:59Z&quot;,
        &quot;Driver&quot;: &quot;local&quot;,
        &quot;Labels&quot;: null,
        &quot;Mountpoint&quot;: &quot;/var/lib/docker/volumes/testvolume/_data&quot;,
        &quot;Name&quot;: &quot;testvolume&quot;,
        &quot;Options&quot;: null,
        &quot;Scope&quot;: &quot;local&quot;
    }
]

% docker run -d -v testvolume:/app/data --name testcontainer nginx
c9e06651da1b2b067a8ecfefefb18ae4f63b05b5b10197bce6e9721806199018

% docker ps
CONTAINER ID   IMAGE     COMMAND                   CREATED          STATUS          PORTS      NAMES
c9e06651da1b   nginx     &quot;/docker-entrypoint.&amp;hellip;&quot;   56 seconds ago   Up 56 seconds   80/tcp     testcontainer
4d16388a956d   nginx     &quot;/docker-entrypoint.&amp;hellip;&quot;   4 minutes ago    Up 4 minutes    80/tcp     mycontainer


% docker stop testcontainer
testcontainer
% docker stop mycontainer
mycontainer
% docker rm testcontainer
testcontainer
% docker rm mycontainer
mycontainer
% docker volume rm testvolume
testvolume&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;Bind Mounts&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;host file system의 특정 파일이나 디렉토리를 컨테이너의 파일 시스템에 마운트 하는 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;gherkin&quot;&gt;&lt;code&gt;+---------------------+      +----------------------+
|   호스트 시스템        |      |    Docker 컨테이너      |
|                     |      |                      |
|  /path/to/data      |      |  /app/data           |
|  (실제 데이터)         |      |  (마운트 포인트)        |
|                     |      |                      |
+---------------------+      +----------------------+&lt;/code&gt;&lt;/pre&gt;
&lt;div data-panel-type=&quot;note&quot;&gt;
&lt;div data-panel-content=&quot;true&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mount(마운트)란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저장된 데이터를 다른 위치(시스템,프로그램)에서 접근할 수 있도록 &lt;b&gt;연결&lt;/b&gt;하는 과정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;로그파일을 호스트의 &amp;lsquo;/var/log/myapp&amp;rsquo;에 저장&lt;/li&gt;
&lt;li&gt;컨테이너의 &amp;lsquo;/app/log&amp;rsquo;에 마운트&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; /app/log는 마운트 포인트, 실제 호스트는 &amp;lsquo;/app/log&amp;rsquo;에 있지만 컨테이너는 마치 자신내부에 데이터가 있는것 처럼 &amp;lsquo;/app/log&amp;rsquo;를 통해 로그 파일에 접근,관리함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &amp;lsquo;/app/log&amp;rsquo; 경로로 접근시 실제 호스트 &amp;lsquo;/var/log/myapp&amp;rsquo;의 내용을 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그파일의 실제 호스트는 &amp;lsquo;/var/log/myapp&amp;rsquo;에 쓰여짐&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; font-size: 1.44em; letter-spacing: -1px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;Bind Mounts 장점&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&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-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;Bind Mounts 사용 사례&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적인 경우, 가능하면 bind Mounts보다 volume을 사용하는게 좋다.&lt;/li&gt;
&lt;li&gt;Docker Host 개발환경과 Container 간 소스코드 또는 빌드된 artifact를 공유
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Maven의 &lt;span&gt;target/&lt;/span&gt; 디렉토리를 Container에 Mount &amp;rarr; Docker Host에서 Maven Project를 빌드할 때마다, Container에서 재 작성된 작성된 JAR/WAR에 접근&lt;/li&gt;
&lt;li&gt;만약 bind mounts 사용한다면 Production-Ready 아티팩트를 Image에 직접 복사할 수 있다.&lt;/li&gt;
&lt;/ol&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;Bind Mounts VS Docker Volume&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-table-width=&quot;760&quot; data-table-local-id=&quot;16c6731b-d66a-4ee2-9ae2-8c25d67c1ded&quot; data-autosize=&quot;false&quot; data-layout=&quot;default&quot; data-number-column=&quot;false&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span&gt;&lt;b&gt;Volume&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span&gt;&lt;b&gt;Bind Mounts&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;관리 방식&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td data-colwidth=&quot;327&quot;&gt;&lt;span&gt;Docker에 의해 관리&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker CLI,API를 통해 생성,삭제,관리됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;td data-colwidth=&quot;337&quot;&gt;&lt;span&gt;사용자가 직접 host system file이나 디렉토리 관리&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;사용시&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td data-colwidth=&quot;327&quot;&gt;&lt;span&gt;호스트 시스템의 Docker 저장소 디렉터리 내에 새 디렉터리가 생성되고 Docker는 해당 디렉터리의 콘텐츠를 관리&lt;/span&gt;&lt;/td&gt;
&lt;td data-colwidth=&quot;337&quot;&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;span&gt;Q. 컨테이너에 저장되면 컨테이너 삭제시 데이터도 삭제 되는가?&lt;/span&gt;&lt;br /&gt;&lt;span&gt;A. 컨테이너 내부에서 데이터를 보고 사용할 수 있지만, 실제 데이터는 호스트의 파일 시스템에 존재&lt;/span&gt;&lt;br /&gt;&lt;span&gt;ex.&lt;/span&gt;&lt;br /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;로그파일을 호스트의 &amp;lsquo;/var/log/myapp&amp;rsquo;에 저장&lt;/li&gt;
&lt;li&gt;컨테이너의 &amp;lsquo;/app/log&amp;rsquo;에 마운트&lt;/li&gt;
&lt;/ol&gt;
&lt;span&gt;(해당 경로로 접근시 실제 호스트 &amp;lsquo;/var/log/myapp&amp;rsquo;의 내용을 사용)&lt;/span&gt;&lt;br /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;로그파일의 실제 호스트는 &amp;lsquo;/var/log/myapp&amp;rsquo;에 쓰여짐&lt;/li&gt;
&lt;/ol&gt;
&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;저장 위치&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td data-colwidth=&quot;327&quot;&gt;&lt;span&gt;Docker가 설정한 특정 경로에 저장&lt;/span&gt;&lt;/td&gt;
&lt;td data-colwidth=&quot;337&quot;&gt;&lt;span&gt;사용자가 지정한 호스트 시스템의 어떤 경로에든 위치&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;장점&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td data-colwidth=&quot;327&quot;&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;/td&gt;
&lt;td data-colwidth=&quot;337&quot;&gt;&lt;span&gt;개발과정에서 실시간으로 데이터를 공유, 업데이트시 사용 (직접 마운트하고 직접 경로 설정을 하기 때문)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;95&quot;&gt;&lt;span&gt;관련 코드&lt;/span&gt;&lt;/td&gt;
&lt;td data-colwidth=&quot;327&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/td&gt;
&lt;td data-colwidth=&quot;337&quot;&gt;&lt;span&gt;docker run -v /home/user/myapp:/var/www/html myimage&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-pm-slice=&quot;1 3 []&quot; data-ke-size=&quot;size26&quot;&gt;tmpfs Mounts&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;tmpfs(temp orary file system) 임시파일 저장 방식, 데이터를 영구 저장이 아닌 휘발성 메모리에 저장한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;tmpfs Mounts 특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;tmpfs mounts를 사용하여 컨테이너 생성시 tmpfs 컨테이너는 컨테이너의 쓰기 가능한 레이어 외부에 파일을 생성 할 수 있음&lt;/li&gt;
&lt;li&gt;volume, bind mounts와 다르게 tmpfs mounts는 일시적이며 호스트 메모리에만 지속되기 때문에 컨테이너 중지시 tmpfs가 제거되고 데이터도 제거된다.&lt;/li&gt;
&lt;li&gt;주로 호스트,Container writable layer에 유지하고 싶지 않은 민감한 파일을 임시로 저장하는데 유용하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;background-color: #f7f7f7; border: #c1c1c1 1px solid; padding: 10px;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q. tmpfs mounts와 컨테이너의 쓰기 가능한 레이어(writable layer) 모두 컨테이너 삭제 시 데이터가 삭제되는데 무슨 차이가 있는건가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style2&quot; data-ke-align=&quot;alignLeft&quot; data-number-column=&quot;false&quot; data-layout=&quot;default&quot; data-autosize=&quot;false&quot; data-table-local-id=&quot;e7c78934-af6f-4563-8cea-72ce3a222f0f&quot; data-table-width=&quot;760&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;span&gt;tmpfs mounts&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;span&gt;container writable layer&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;151&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/td&gt;
&lt;td data-colwidth=&quot;355&quot;&gt;&lt;span&gt;호스트 시스템의 메모리(램)에 데이터를 저장&lt;/span&gt;&lt;/td&gt;
&lt;td data-colwidth=&quot;253&quot;&gt;&lt;span&gt;디스크에 저장&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;151&quot;&gt;&lt;span&gt;장점&lt;/span&gt;&lt;/td&gt;
&lt;td data-colwidth=&quot;355&quot;&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;/td&gt;
&lt;td data-colwidth=&quot;253&quot;&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;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;151&quot;&gt;&lt;span&gt;특징&lt;/span&gt;&lt;/td&gt;
&lt;td data-colwidth=&quot;355&quot;&gt;&lt;span&gt;컨테이너가 중지/삭제되면 메모리에서 데이터가 사라짐&lt;/span&gt;&lt;/td&gt;
&lt;td data-colwidth=&quot;253&quot;&gt;&lt;span&gt;컨테이너가 삭제해야만 해당 레이어에 저장된 모든 데이터도 함께 삭제&lt;/span&gt;&lt;br /&gt;&lt;span&gt;(중지시 데이터 그대로 유지)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;151&quot;&gt;&lt;span&gt;사용 방식&lt;/span&gt;&lt;/td&gt;
&lt;td data-colwidth=&quot;355&quot;&gt;&lt;span&gt;일시적 사용(세션 데이터,임시 파일 처리)&lt;/span&gt;&lt;br /&gt;&lt;span&gt;주로 민감함 데이터의 임시저장시 사용&lt;/span&gt;&lt;/td&gt;
&lt;td data-colwidth=&quot;253&quot;&gt;&lt;span&gt;일반적인 데이터 저장과 어플리케이션의 작업에 사용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;tmpfs Mounts 제한사항&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;tmpfs mounts는 volume, bind mounts와 다르게 컨테이너 간에 마운트를 공유할 수 없다&lt;/li&gt;
&lt;li&gt;Linux에서 Docker를 실행하는 경우에만 사용 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*참고자료&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.docker.com/storage/volumes/&quot;&gt;https://docs.docker.com/storage/volumes/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.docker.com/storage/bind-mounts/&quot;&gt;https://docs.docker.com/storage/bind-mounts/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.docker.com/storage/tmpfs/&quot;&gt;https://docs.docker.com/storage/tmpfs/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Tmpfs&quot;&gt;https://en.wikipedia.org/wiki/Tmpfs&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/dtevangelist/docker-%EA%B8%B0%EB%B3%B8-5-8-volume%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-data-%EA%B4%80%EB%A6%AC-9a9ac1db978c&quot;&gt;https://medium.com/dtevangelist/docker-%EA%B8%B0%EB%B3%B8-5-8-volume%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-data-%EA%B4%80%EB%A6%AC-9a9ac1db978c&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://seosh817.tistory.com/374&quot;&gt;https://seosh817.tistory.com/374&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@hoplin/Docker-docker-volume&quot;&gt;https://velog.io/@hoplin/Docker-docker-volume&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://belowthemalt.com/2021/12/08/mount-volumes-to-persist-data-in-local-initialize-database-in-docker/&quot;&gt;https://belowthemalt.com/2021/12/08/mount-volumes-to-persist-data-in-local-initialize-database-in-docker/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/AmazonECS/latest/bestpracticesguide/storage.html&quot;&gt;https://docs.aws.amazon.com/AmazonECS/latest/bestpracticesguide/storage.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://oertx.highered.texas.gov/courseware/lesson/2379/student/?section=5&quot;&gt;https://oertx.highered.texas.gov/courseware/lesson/2379/student/?section=5&lt;/a&gt;&lt;a href=&quot;https://oertx.highered.texas.gov/courseware/lesson/2379/student/?section=5&quot;&gt;https://oertx.highered.texas.gov/courseware/lesson/2379/student/?section=5&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라하며 배우는 도커와 CI환경 강의&lt;/p&gt;</description>
      <category>DOCKER</category>
      <author>PeonyF</author>
      <guid isPermaLink="true">https://peonyf.tistory.com/204</guid>
      <comments>https://peonyf.tistory.com/entry/Docker-Docker-Volume#entry204comment</comments>
      <pubDate>Tue, 2 Jan 2024 19:59:52 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] Docker 최적화</title>
      <link>https://peonyf.tistory.com/entry/Docker-Docker-%EC%B5%9C%EC%A0%81%ED%99%94</link>
      <description>&lt;h1 data-pm-slice=&quot;1 1 []&quot;&gt;1. 생성된 레이어 재사용(캐싱)&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기존코드1&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker이미지 빌드시 Dockerfile의 각 명령어를 실행 &amp;rarr; 해당 결과들을 새로운 레이어로 저장한다.&lt;/li&gt;
&lt;li&gt;아래 코드는 소스 코드중 어떤 파일이든 변경되면 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;COPY ./ ./&lt;/span&gt; 이후의 모든 레이어가 다시 빌드된다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 소스의 작은 변경이라도 &lt;span&gt;RUN npm install&lt;/span&gt; 가 다시 실행된다.&lt;/p&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;FROM node:10
WORKDIR /usr/src/app
COPY ./ ./
RUN npm install
CMD [&quot;node&quot;,&quot;server.js&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;수정코드1&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수정된 이유&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span&gt;package.json&lt;/span&gt; 먼저 복사
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span&gt;package.json&lt;/span&gt;에 변경사항이 없다 &amp;rarr; &lt;span style=&quot;background-color: #dddddd;&quot;&gt;RUN npm install&lt;/span&gt; 명령어 까지의 모든 레이어 캐싱되어 재사용(&lt;span data-text-custom-color=&quot;#403294&quot;&gt;npm 재설치 없이 빠르게 빌드 가능&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;package.json&lt;/span&gt;에 변경사항이 있다 &amp;rarr; &lt;span style=&quot;background-color: #dddddd;&quot;&gt;RUN npm install &lt;/span&gt;실행&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;이후 코드를 수정한 부분이 있는 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;COPY ./ ./ &lt;/span&gt;를 복사&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;FROM node:10
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install
COPY ./ ./
CMD [&quot;node&quot;,&quot;server.js&quot;]&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 파일을 한번에 복사한 후 필요한 Python 패키지를 설치하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;FROM python:3.8-slim
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
EXPOSE 8080
ENTRYPOINT [&quot;python&quot;]
CMD [&quot;run.py&quot;] &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;/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;&quot;&gt;WORKDIR /app&lt;/span&gt; 의 순서 변경 &amp;rarr; 작업 디렉토리를 명확히 하고, 모든 파일 경로와 명령 실행의 기준점을 설정하기 위함&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;requirements.txt&lt;/span&gt;를 먼저 복사 &amp;rarr; 변경이 없을 경우 &lt;span&gt;pip install&lt;/span&gt; 단계를 다시 실행하지 않음(기존 레이어 재사용)&lt;/li&gt;
&lt;li&gt;이후 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;COPY ./app&lt;/span&gt; 명령어로 application의 나머지 부분 복사 &amp;rarr; 변경이 없을 경우 기존 레이어 재사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;FROM python:3.8-slim
WORKDIR /app
COPY requirements.txt ./requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
COPY ./app
EXPOSE 8080
#ENTRYPOINT : 컨테이너가 시작될 때 실행할 기본 명령을 설정
#컨테이너가 시작될 때 항상 Python 인터프리터를 사용하여 지정된 파이썬 스크립트(CMD에서 지정된 run.py 같은)를 실행
ENTRYPOINT[&quot;python&quot;]
CMD[&quot;run.py&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;캐싱&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변경이 잦은 파일들은 Dockerfile의 뒤에 COPY하는것이 좋고, 의존성 파일(ex.&lt;span&gt;requirements.txt&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;Docker이미지 빌드시 Dockerfile의 각 명령어를 실행하면서 해당 명령어의 결과 캐싱&lt;/li&gt;
&lt;li&gt;만약 특정 명령어까지 변경사항이 없다면 Docker는 그 부분까지 캐싱된 결과(layer)를 재사용함&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;h1&gt;2. Dockerfile 최적화&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;더 작은 기본 이미지 사용&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ex.multi-stage, 완전한 OS(ubuntu)대신 경량 Alpine Linux 이미지를 기본으로 사용&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# 변경전
FROM ubuntu:20.04
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y python3-pip
...

# 변경후
FROM alpine:3.12
RUN apk add --no-cache python3 py3-pip
...&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;불필요한 파일 제거&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.dockerignore 파일을 사용하여 빌드 컨텍스트에서 파일이나 디렉터리를 제외&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;# 버전관리 시스템 폴더
.git
.gitignore
.svn
.hg

# 빌드 도구 관련 파일 및 폴더
Dockerfile
Dockerfile.*
*docker-compose.yml
.dockerenv

#종속성 관련 폴더(파이썬)
.pip
.virtualenv
venv
.env

# 로그 파일 및 디렉토리
*.log
logs

# 임시파일 및 캐시파일
*.tmp
*.temp
*.cache

# 개발 도구 설정 파일
.vscode
.idea
*.swp

# 테스트 및 문서파일
tests
docs
doc
README.md

# 빌드 결과물 미 배포파일
dist
build
out

# 운영체제 관련 파일
.DS_Store
Thumbs.db&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;레이어 수 최소화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제점 : 각 명령어는 새레이어를 생성함 &amp;rarr; 레이어가 많으면 빌드 프로세스 속도 드려짐 &amp;rarr; Docker image 크기 늘어남&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;RUN apt-get update
RUN apt-get install -y package1
RUN apt-get install -y package2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결점 : RUN 명령을 사용해 여러 주문을 단일 명령어로 결합&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;RUN apt-get update &amp;amp;&amp;amp; \
    apt-get install -y package1 &amp;amp;&amp;amp; \
    apt-get install -y package2&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ENV,올바른 CMD 및 ENTRYPOINT 사용&lt;/h2&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;#ENV로 환경 설정 지정
FROM node:14
ENV NODE_ENV=production&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;#ENTRYPOINT로 Nginx 시작하라고 명령함
ENTRYPOINT [&quot;nginx&quot;, &quot;-g&quot;, &quot;daemon off;&quot;]
CMD [&quot;-c&quot;, &quot;/etc/nginx/nginx.conf&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;3. Multi-Stage Build사용&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Multi-stage 코드&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Builder 단계: Builder 단계에서 빌드된 결과물 생성 및 이 &lt;span style=&quot;color: #8a3db6;&quot; data-text-custom-color=&quot;#403294&quot;&gt;중간결과물&lt;/span&gt;을 캐시함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미지에 포함되는 파일(O) : 설치된 Python 패키지, application 코드(/app)&lt;/li&gt;
&lt;li&gt;이미지에 제거되는 파일(X) :
&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;빌드파일 : gradlew,gradle 등 빌드과정을 자동화하는 스크립트,설정파일은 빌드후에는 필요없음&lt;/li&gt;
&lt;li&gt;중간 생성파일: 컴파일 과정에서 생성되는 클래스,로그 파일등은 필요없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Deployer단계 : Builder 단계에서 빌드된 결과물(이미지 레이어)를 가져와서 최종 이미지 구성
&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;&quot;&gt;COPY --from=builder&lt;/span&gt; 를 통해 Builder 단계에서 필요한 결과물만 가져온다(빌드에 필요한 패키지, 라이브러리, 빌드된 소스 코드 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-level=&quot;2&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;# Builder 단계
FROM python:3.8-alpine AS builder
RUN apk update &amp;amp;&amp;amp; apk add --no-cache make &amp;amp;&amp;amp; apk add --no-cache libpq-dev g++
WORKDIR /app
COPY requirements* ./
RUN pip install --no-cache-dir -r requirements-prod.txt
COPY Makefile . 
COPY src ./src

# Deployer(배포자) 단계
FROM python:3.8-alpine AS deployer
COPY --from=builder /usr/local/lib/python3.8/site-packages /usr/local/lib/python3.8/site-packages
COPY --from=builder /app /app
RUN apk update &amp;amp;&amp;amp; apk add --no-cache make
WORKDIR /app

CMD [&quot;make&quot;, &quot;run-server&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;background-color: #f7f7f7; border: #c1c1c1 1px solid; padding: 10px;&quot;&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;질문1. 만약&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;Builder 단계&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;혹은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;Deployer(배포자) 단계&lt;/span&gt;에서 코드 수정이 생긴다면?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;Builder 단계&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;코드 수정시 : 만약 requirements.txt가 변경시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;pip install&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 통해 재설치 및 새로운&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #8a3db6; text-align: left;&quot;&gt;중간결과물&lt;/span&gt;을 생성한다. 이후 변경된&lt;span data-text-custom-color=&quot;#403294&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #8a3db6; text-align: left;&quot;&gt;중간결과물&lt;/span&gt;&lt;/span&gt;을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;Deployer(배포자) 단계&lt;/span&gt;에서 재빌드되어 최종 이미지에 반영됨&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Deployer(배포자) 단계&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;코드 수정시 : 캐시된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;Builder 단계&lt;/span&gt;의 결과물은 그대로 사용,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;Deployer(배포자) 단계&lt;/span&gt;에서 변경된 사항을 반영하기 위해 변경된 부분의 명령부터 이후의 모든 명령을 다시 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;질문2. Multi-Stage Build에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #8a3db6; text-align: left;&quot;&gt;중간결과물&lt;/span&gt;을 사용해 특정 레이어의 결과물을 이전 단계(builder 단계)에서 가져와서 현재 이미지로 복사하는데, 일반 Docker 빌드와 레이어시에도 동일한가?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반 Docker빌드시 각 명령어들이 순서대로 실행 &amp;rarr; 새로운 레이어가 이전 레이어 위에 순차적으로 쌓임 &amp;rarr; 최종 이미지 생성&lt;/li&gt;
&lt;li&gt;일반 Docker빌드시 각 단계에서 생성된 레이어들을 건너뛰거나,선택적으로 사용하는게 아닌&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;u&gt;모든 레이어가 최종 이미지에 포함됨&lt;/u&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Multi-Stage Build&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FROM문을 사용해 단계별로 이미지를 구성하고, 마지막 단계에서만 필요한 파일을 가져온다.&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;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;a href=&quot;https://benriemer.medium.com/speed-up-docker-desktop-d676c9fe82de&quot;&gt;https://benriemer.medium.com/speed-up-docker-desktop-d676c9fe82de&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라하며 배우는 도커와 CI환경 강의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.annotation-ai.com/python-docker-img-optimization/&quot;&gt;https://blog.annotation-ai.com/python-docker-img-optimization/&lt;/a&gt;&lt;/p&gt;</description>
      <category>DOCKER</category>
      <author>PeonyF</author>
      <guid isPermaLink="true">https://peonyf.tistory.com/203</guid>
      <comments>https://peonyf.tistory.com/entry/Docker-Docker-%EC%B5%9C%EC%A0%81%ED%99%94#entry203comment</comments>
      <pubDate>Thu, 28 Dec 2023 19:52:06 +0900</pubDate>
    </item>
    <item>
      <title>[Docker]  Docker Container2 - 코드로 보는 개념</title>
      <link>https://peonyf.tistory.com/entry/Docker-%08Docker-Container2-%EC%BD%94%EB%93%9C%EB%A1%9C-%EB%B3%B4%EB%8A%94-%EA%B0%9C%EB%85%90</link>
      <description>&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Docker 컨테이너내에 구성요소들이 적용될수있는 이유는?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;Dockerfile을 통해 구성요소들을 설정해 준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;* Dockerfile 내용&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703567649135&quot; class=&quot;dockerfile&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;FROM adptopenjdk:8-jdk-hotspot AS builder #베이스이미지+별칭
COPY gradlew . #gradlew 복사
COPY gradle gradle #gradle 복사
COPY build.grade . #build.gradle 복사
COPY settings.gradle #settings.gradle 복사
COPY src src #웹 어플리케이션 소스 복사
RUN chmod +x ./gradlew #gradlew 실행권한 부여
RUN ./gradlew bootJar #gradlew를 사용하여 실행 가능한 jar 파일 생성

FROM adoptopenjdk:8-jdk-hotspot #베이스 이미지
COPY --from=builder build/libs/*/jar app.jar #builder 이미지에서 build/libs/*.jar 파일을 app.jar로 복사

EXPOSE 8080 #컨테이너 Port 노출
ENTRYPOINT [&quot;java&quot;,&quot;-jar&quot;,&quot;/app.jar&quot;] #jar 파일 실행&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;div style=&quot;background-color: #f7f7f7; border: #c1c1c1 1px solid; padding: 10px;&quot;&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;질문 1. gradlew이란?&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;gradle wrapper의 줄임말로 프로젝트에 gradle을 설치할 필요없이 어디서나 동일한 버전의 gradle을 사용하게 해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;gradlew를 사용하면 gradle이 사전에 설치되어있지 않아도 된다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;gradlew 스크립트가 필요한 gradle버전을 자동으로 다운로드/실행한다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;질문 1-1. 왜 RUN&amp;nbsp;chmod&amp;nbsp;+x&amp;nbsp;./gradlew를 해주는가?&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;- 리눅스 or macOS에서 스크립트 파일을 실행하려면, 해당 파일의 실행권한이 필요함.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 소스코드를 Docker 컨테이너로 복사시 파일 권한이 유지되지 않을 수 있어 Dockerfile에 명시적으로 실행 권한 부여&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;질문2. 이 코드는 멀티-스테이지 이다. 어떻게 알아볼수있는가?&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- FROM 명령어가 두번 사용됨 (첫번째 FROM : 빌드과정에 사용될 베이스 이미지 정하고 builder라는 별명 붙임, 두번째 FROM : 최종이미지에 사용될 베이스 이미지를 지정-&amp;gt; application을 실행하는데 필요한 환경만을 포함)&lt;/p&gt;
&lt;pre id=&quot;code_1703567649137&quot; class=&quot;dockerfile&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Use multi-stage builds
# syntax=docker/dockerfile:1
FROM golang:1.21
WORKDIR /src
COPY &amp;lt;&amp;lt;EOF ./main.go
package main

import &quot;fmt&quot;

func main() {
  fmt.Println(&quot;hello, world&quot;)
}
EOF
RUN go build -o /bin/hello ./main.go

FROM scratch
COPY --from=0 /bin/hello /bin/hello
CMD [&quot;/bin/hello&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- &quot;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;COPY --from=builder build/libs/*/jar app.jar&quot;를 통해 첫번째 스테이지('builder')에서 생성된 파일(JAR 파일)을 두번째 스테이지로 복사함을 통해 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;질문 2-1. 멀티-스테이지 빌드의 장점은?&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;- Generated images are smaller : 최종 이미지가 일반적으로 일반 빌드에서 생성된 이미지보다&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;훨씬 작다&lt;/span&gt;. (결과 이미지에는 application에 필요한 내용만 포함되지 때문)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;- Faster deployment: 이미지가 작을수록 전송시간, CI/CD 빌드 속도가 빨라지고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;배포시간이 빨라지며 성능이 향상된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;질문 2-1-1. 그렇게 좋다면 멀티-스테이지 빌드를 모든 dockerfile에서 사용해야 하는거 아닌가?&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;- 멀티-스테이지 빌드를 사용 O&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;대규모 또는 복잡한 어플리케이션 : 컴파일이 필요한 언어(Java,C++,Go)를 사용하는 대규모 어플리케이션의 경우 빌드 도구와 런타임 환경을 분리하는것이 좋다.&lt;/li&gt;
&lt;li&gt;최적화된 이미지 크기 : 빌드 과정에서 생성되는 임시 파일,도구를 최종이미지에 제거하여 이미지 크기르르 줄이고 싶을때 유용하다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;기본 이미지 빌드 후 이미지 크기 확인하여 예상보다 클경우 멀티-스테이지 빌드 적용을 고민한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;멀티-스테이지 빌드를 사용 X&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단순한 어플리케이션, 작은 규모의 이미지 : 사용하는 언어나 프레임 워크가 이미 최소화된 이미지 크기를 제공시&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;질문 2-1-2. 컴파일이 필요한 언어의 경우&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;멀티-스테이지 빌드를 사용 O라고 했는데 파이썬은은 그럼&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;멀티-스테이지 빌드를 사용 X인가?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;- 파이썬은 인터프리터 언어(컴파일 과정없이 실행 시간에 직접 해석되어 실행)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/s&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;- 파이썬은 간단한 빌드과정 즉 소스코드가 직접 실행되므로 복잡한 빌드과정이 필요하지 않아 대부분 소스코드와 필요한 외부&amp;nbsp;라이브러리를&amp;nbsp;이미지에&amp;nbsp;복사하는&amp;nbsp;것만으로&amp;nbsp;충분하다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/s&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;예외) 파이썬&amp;nbsp;프로젝트에서&amp;nbsp;C/C++로&amp;nbsp;작성된&amp;nbsp;네이티브&amp;nbsp;확장&amp;nbsp;모듈을&amp;nbsp;컴파일해야&amp;nbsp;하는&amp;nbsp;경우&lt;/s&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;크기,상황 에 따라 다른것 같음(구글링시에 찬반의견보단 어떻게 python을 multi-staging build하냐 라는 글들만 있음)&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;1556&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KqmOs/btsCyI3Aw8r/pR37K3hhkTGfACBmLkYmz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KqmOs/btsCyI3Aw8r/pR37K3hhkTGfACBmLkYmz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KqmOs/btsCyI3Aw8r/pR37K3hhkTGfACBmLkYmz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKqmOs%2FbtsCyI3Aw8r%2FpR37K3hhkTGfACBmLkYmz0%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;702&quot; height=&quot;1556&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;1556&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사용 예시 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://blog.annotation-ai.com/python-docker-img-optimization/&quot;&gt;https://blog.annotation-ai.com/python-docker-img-optimization/&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703567649139&quot; class=&quot;dockerfile&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM python:3.8-alpine AS builder

RUN apk update &amp;amp;&amp;amp; apk add --no-cache make &amp;amp;&amp;amp; apk add --no-cache libpq-dev g++

WORKDIR /app
COPY requirements* ./
RUN pip install --no-cache-dir -r requirements-prod.txt
COPY Makefile . 
COPY src ./src


FROM python:3.8-alpine AS deployer
COPY --from=builder /usr/local/lib/python3.8/site-packages /usr/local/lib/python3.8/site-packages
COPY --from=builder /app /app
RUN apk update &amp;amp;&amp;amp; apk add --no-cache make
WORKDIR /app

CMD [&quot;make&quot;, &quot;run-server&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;질문 2-2. 위의 java dockerfile의 경우 왜 멀티-스테이지를 사용하는가? 각 필요파일을 복사해서 jar파일 만들고 그걸 다시 복사하는건데.&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;- 불필요한 파일 제거&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;첫번째 스테이지에서 최종 실행 이미지에 필요없는 것들이 만들어진다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;ex. 소스코드 : 빌드를 위해 필요하지만, 실행파일이 생성되면 필요없음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 빌드파일 : gradlew,gradle 등 빌드과정을 자동화하는 스크립트,설정파일은 빌드후에는 필요없음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 중간 생성파일: 컴파일 과정에서 생성되는 클래스,로그 파일등은 필요없음&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;질문 2-2-1. 그럼 '&lt;span style=&quot;color: #111827; text-align: left;&quot;&gt;adoptopenjdk:8-jdk-hotspot'를 왜 또하는가?&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;java application을 실행하는데 필요한 최소한의 java 라이브러리와 도구들이 포함된다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;* Dockerfile  build&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703567649141&quot; class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;docker build -t deploy-test:0.0.1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;* Dockerfile  실행&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703567649141&quot; class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;docker run -d -p 8080:8080 deploy-test:0.0.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;-python 위의 코드의 경우 (&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;my-running-app :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;Docker 컨테이너의 이름)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703567649142&quot; class=&quot;stata&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;docker run -d --name my-running-app deploy-test:0.0.1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고자료&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.docker.com/guides/walkthroughs/what-is-a-container/#what-is-a-container&quot;&gt;https://docs.docker.com/guides/walkthroughs/what-is-a-container/#what-is-a-container&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.docker.com/config/containers/runmetrics/&quot;&gt;https://docs.docker.com/config/containers/runmetrics/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.netapp.com/devops-solutions/what-are-containers/&quot;&gt;https://www.netapp.com/devops-solutions/what-are-containers/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.linkedin.com/pulse/cgroups-docker-pavan-shukla/&quot;&gt;https://www.linkedin.com/pulse/cgroups-docker-pavan-shukla/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://inma.tistory.com/148&quot;&gt;https://inma.tistory.com/148&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.docker.com/build/building/multi-stage/&quot;&gt;https://docs.docker.com/build/building/multi-stage/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.cherryservers.com/blog/docker-multistage-build&quot;&gt;https://www.cherryservers.com/blog/docker-multistage-build&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.annotation-ai.com/python-docker-img-optimization/&quot;&gt;https://blog.annotation-ai.com/python-docker-img-optimization/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.vantage-ai.com/vantage101/chapter-9-docker&quot;&gt;https://www.vantage-ai.com/vantage101/chapter-9-docker&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kimjingo.tistory.com/38&quot;&gt;https://kimjingo.tistory.com/38&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/echo-devblog/%EB%8F%84%EC%BB%A4%EB%A5%BC-%EB%8F%84%EC%9E%85%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-1-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EA%B8%B0%EC%88%A0-%EC%9B%90%EB%A6%AC-90a28c14024e&quot;&gt;https://medium.com/echo-devblog/%EB%8F%84%EC%BB%A4%EB%A5%BC-%EB%8F%84%EC%9E%85%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-1-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EA%B8%B0%EC%88%A0-%EC%9B%90%EB%A6%AC-90a28c14024e&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/51765555/what-namespaces-are-shared-among-containers-in-a-kubernetes-pod&quot;&gt;https://stackoverflow.com/questions/51765555/what-namespaces-are-shared-among-containers-in-a-kubernetes-pod&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://platform.sh/blog/the-container-is-a-lie/&quot;&gt;https://platform.sh/blog/the-container-is-a-lie/&lt;/a&gt;&lt;/p&gt;</description>
      <category>DOCKER</category>
      <author>PeonyF</author>
      <guid isPermaLink="true">https://peonyf.tistory.com/201</guid>
      <comments>https://peonyf.tistory.com/entry/Docker-%08Docker-Container2-%EC%BD%94%EB%93%9C%EB%A1%9C-%EB%B3%B4%EB%8A%94-%EA%B0%9C%EB%85%90#entry201comment</comments>
      <pubDate>Tue, 26 Dec 2023 19:16:41 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] Docker Image</title>
      <link>https://peonyf.tistory.com/entry/Docker-Docker-Image</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;395&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/spoU5/btsCAkA7Vfo/VKAVbS71T1g3Pfnm55Acpk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/spoU5/btsCAkA7Vfo/VKAVbS71T1g3Pfnm55Acpk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/spoU5/btsCAkA7Vfo/VKAVbS71T1g3Pfnm55Acpk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FspoU5%2FbtsCAkA7Vfo%2FVKAVbS71T1g3Pfnm55Acpk%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;750&quot; height=&quot;395&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;395&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0px0E/btsCzIvpqWA/AsuCj0dYjhIObDHb5n8KQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0px0E/btsCzIvpqWA/AsuCj0dYjhIObDHb5n8KQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0px0E/btsCzIvpqWA/AsuCj0dYjhIObDHb5n8KQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0px0E%2FbtsCzIvpqWA%2FAsuCj0dYjhIObDHb5n8KQK%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;1000&quot; height=&quot;362&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;362&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;h1&gt;Docker Image란?&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;An image is a read-only template with instructions for creating a Docker container. Often, an image is based on another image, with some additional customization. For example, you may build an image which is based on the &lt;span&gt;ubuntu&lt;/span&gt; image, but installs the Apache web server and your application, as well as the configuration details needed to make your application run&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker Container를 만들기 위한 명령이 있는 읽기 전용 템플릿.&lt;/li&gt;
&lt;li&gt;어떤 이미지의 경우 다른 이미지 기반 + 추가적인 사용자의 정의 으로 되어있다.&lt;/li&gt;
&lt;li&gt;공개 Docker image는 Docker Hub에 있어서 여기서 관련 공개 이미지를 찾는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex.ubuntu image+aphache webserver + application + application을 실행하는데 필요한 세부정보&lt;/p&gt;
&lt;div data-panel-type=&quot;info&quot;&gt;
&lt;div data-panel-content=&quot;true&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker Container&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker Image를 통해 application을 실행하기 위해 모든것(코드,런타임,시스템 도구,시스템 라이브러리 설정등)을 포함하고 있는 기술인데, 이 기술을 통해 어느 환경에서나 일관된 방식으로 실행할수 있다.&lt;/p&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;/div&gt;
&lt;/div&gt;
&lt;h1&gt;Docker Container VS Docker Image&lt;/h1&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 218px;&quot; border=&quot;1&quot; data-table-width=&quot;760&quot; data-table-local-id=&quot;20848c90-5756-4848-b8a2-589a2bba6d99&quot; data-autosize=&quot;false&quot; data-layout=&quot;default&quot; data-number-column=&quot;false&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px; text-align: center;&quot;&gt;&lt;b&gt;&lt;span&gt;Docker Container&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 18px; text-align: center;&quot;&gt;&lt;b&gt;&lt;span&gt; Docker Image&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 60px;&quot;&gt;
&lt;td style=&quot;height: 60px;&quot;&gt;&lt;span&gt; Docker Image를 기반으로 실행되는 각각 컨테이너가 그 이미지의 &amp;ldquo;실행버전&amp;rdquo; (인스턴스화)&lt;/span&gt;&lt;br /&gt;&lt;span&gt;(이미지의 상태를 복제하여 실행함)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 60px;&quot;&gt;&lt;span&gt; Docker Image는 Docker Container의 소스 코드&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;&lt;span&gt; Docker Image는 Docker Container의 전제조건&lt;/span&gt;&lt;br /&gt;&lt;span&gt;(Dockerfile로부터 이미지를 빌드한 이미지를 기반으로 컨테이너를 실행)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;&lt;span&gt;Dockerfile은  Docker Image의 필수 구성요소&lt;/span&gt;&lt;br /&gt;&lt;span&gt;(Dockerfile로부터 이미지를 빌드)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;&lt;span&gt;Docker Container는 유저들끼리 공유할수 없다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;(컨테이너는 실행 중인 이미지 인스턴스여서 동적이고 일시적이라 공유X)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 40px;&quot;&gt;&lt;span&gt;Docker Image는 Docker Hub를 통해 사용자간에 공유 가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 60px;&quot;&gt;
&lt;td style=&quot;height: 60px;&quot;&gt;&lt;span&gt;Docker Container는 컨테이너가 실행중일때 사용자가 컨테이너 내부에 들어가 바로 수정 가능하다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;(docker exec 명령어 사용)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 60px;&quot;&gt;&lt;span&gt;Docker Image를 수정하기 위해서는 Dockerfile를 수정해야한다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;760&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1130&quot; data-origin-height=&quot;527&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tekma/btsCLqGsLeY/9USceyZGxg3s5IkRk4BAPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tekma/btsCLqGsLeY/9USceyZGxg3s5IkRk4BAPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tekma/btsCLqGsLeY/9USceyZGxg3s5IkRk4BAPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ftekma%2FbtsCLqGsLeY%2F9USceyZGxg3s5IkRk4BAPK%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;1130&quot; height=&quot;527&quot; data-origin-width=&quot;1130&quot; data-origin-height=&quot;527&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;Docker Image 특징&lt;/h1&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;도커 이미지들은 Docker Hub를 통해 버전 관리 및 배포(push &amp;amp; pull)가 가능하다&lt;/li&gt;
&lt;li&gt;다양한 API가 제공되어 원하는 만큼 자동화가 가능하다&lt;/li&gt;
&lt;li&gt;도커는 Dockerfile이란 파일로 이미지를 만든다. 이 파일엔 소스와 함께 의존성 패키지등 사용했던 설정 파일을 버전 관리하기 쉽게 명시되어 누구나 이미지 생성과정을 확인,수정이 가능하다.&lt;/li&gt;
&lt;li&gt;도커 이미지는 플랫폼에 독립적이다&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Docker Image 구성&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex.&lt;span data-text-custom-color=&quot;#6554c0&quot;&gt;ubuntu image+aphache webserver + application + application&lt;/span&gt;을 실행하는데 필요한 세부정보&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-table-width=&quot;760&quot; data-table-local-id=&quot;a2ddead4-3ab0-498d-bfba-a95936c54989&quot; data-autosize=&quot;false&quot; data-layout=&quot;default&quot; data-number-column=&quot;false&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;147&quot;&gt;&lt;span&gt;&lt;b&gt;Base Image&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td data-colwidth=&quot;611&quot;&gt;&lt;span&gt;Dockerfile을 작성시 시작점이 되는 이미지(최소한의 운영체제,필수 구성 요소 포함)&lt;/span&gt;&lt;br /&gt;&lt;span&gt; ex. &lt;span data-text-custom-color=&quot;#6554c0&quot;&gt;base image: ubuntu&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;147&quot;&gt;&lt;span&gt;&lt;b&gt;Parent Image&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td data-colwidth=&quot;611&quot;&gt;&lt;span&gt;base image기반으로 새로운 image를 만드는데 이것을 parent Image라고 한다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;여기서 parent imagesms dockerfile에서 &amp;ldquo;FROM&amp;rdquo; 명령어를 사용해서 지정된다&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;b&gt;FROM python:3.8&lt;/b&gt; &amp;rarr; Python 3.8이 설치된 이미지를 부모 이미지로 사용하겠다는 것을 의미&lt;/span&gt;&lt;br /&gt;&lt;span&gt;ex. 만약 Ubuntu image + Apache webserver + Application + Application의 세부 정보를 기반으로 다른 이미지를 만들 경우&lt;span data-text-custom-color=&quot;#6554c0&quot;&gt; Ubuntu image + Apache webserver + Application + Application&lt;/span&gt;가 parent Image&lt;/span&gt;&lt;br /&gt;&lt;span&gt;만약 다른 이미지를 만드는 기반으로 사용된다면, 그때 그 이미지는 &quot;parent image&quot;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;147&quot;&gt;&lt;span&gt;&lt;b&gt;Layers&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td data-colwidth=&quot;611&quot;&gt;&lt;span&gt;레이어란 기존 이미지에 추가적은 파일이 필요할때 해당 파일을 추가하는 개념이다. (다시 다운로드 x)&lt;/span&gt;&lt;br /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이미지는 여러개의 읽기 전용 layer로 구성&lt;/li&gt;
&lt;li&gt;파일 추가시 새로운 layer생성&lt;/li&gt;
&lt;li&gt;docker는 여러개의 layer를 묶어 하나의 파일 시스템으로 사용할수있게 함&lt;/li&gt;
&lt;/ol&gt;
&lt;span&gt;+ Docker Hub 및 개인 저장소에 이미지 공유시 바뀐부분(Layer=image)만 주고받기 가능하다&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;ex.&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Aphache webserver Layer : &lt;span&gt;RUN&lt;/span&gt; 명령어를 사용해 해당 webserver설치&lt;/li&gt;
&lt;li&gt;Application Layer : &lt;span&gt;COPY&lt;/span&gt;, &lt;span&gt;RUN&lt;/span&gt; 명령어를 사용해 application file 복사및 필요 의존성 설치&lt;/li&gt;
&lt;li&gt;Application 세부정보 Layer : &lt;span&gt;ENV&lt;/span&gt;, &lt;span&gt;COPY&lt;/span&gt;, &lt;span&gt;CMD&lt;/span&gt; 명령어를 사용해 환경변수 설정,구성 파일 복사, 실행 명령 정의등 세부 설정 포함&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;147&quot;&gt;&lt;span&gt;&lt;b&gt;Docker Registry&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td data-colwidth=&quot;611&quot;&gt;&lt;span&gt;Docker image를 저장/배포함(ex.Docker Hub)&lt;/span&gt;&lt;br /&gt;&lt;span&gt;layer 저장 : Docker image를 Docker registry에 push하면 각 layer는 개별적으로 업로드,저장됨 &amp;rarr; 필요한 layer만 다운로드해서 이미지를 재구성 가능하게 한다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;layer 공유 : 재사용성을 높이기 위해 같은 베이스 이미지 사용시 서로 다른 이미지들을 해당 베이스 레이어를 공유 &amp;rarr; 중복 다운로드 방지,저장 공간 절약&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의 경우&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Base Image&lt;/h3&gt;
&lt;div data-level=&quot;1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 서버용 Dockerfile :&lt;b&gt; &lt;/b&gt;&lt;span&gt;FROM nginx:latest&lt;/span&gt; : 여기서 &quot;nginx:latest&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 서버용 Dockerfile : &lt;span&gt;FROM mysql:5.7&lt;/span&gt; : 여기서 &quot;mysql:5.7&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백그라운드 작업용 Dockerfile : &lt;span&gt;FROM alpine:latest&lt;/span&gt; : 여기서 &quot;alpine:latest&lt;/p&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Parent Image&lt;/h3&gt;
&lt;div data-level=&quot;1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 Dockerfile에서 지정된 &lt;span&gt;FROM&lt;/span&gt; 명령어의 이미지(&quot;nginx:latest&quot;, &quot;mysql:5.7&quot;, &quot;alpine:latest&quot;)는 각각의 Dockerfile로 만들어지는 이미지의 &quot;부모 이미지&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &quot;부모 이미지&quot;는 기본적으로 &quot;베이스 이미지&quot;와 같은 의미로 사용되고 있다.&lt;/p&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Layers&lt;/h3&gt;
&lt;div data-level=&quot;1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 서버용 Dockerfile &amp;rarr; &lt;b&gt; &lt;/b&gt;&lt;span&gt;COPY ./default.conf /etc/nginx/conf.d/default.conf&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 설정 파일을 nginx 설정 디렉토리로 복사하는 레이어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 서버용 Dockerfile &amp;rarr; &lt;span&gt;ENV MYSQL_ROOT_PASSWORD=my-secret-pw&lt;/span&gt; ,&lt;span&gt;ENV MYSQL_DATABASE=mydatabase&lt;/span&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;백그라운드 작업용 Dockerfile &amp;rarr;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RUN apk add --no-cache dcron&lt;/span&gt; : Alpine Linux에 cron 작업 관리자를 설치하는 레이어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;COPY crontab.txt /etc/crontabs/root&lt;/span&gt; : 크론 작업을 위한 스케줄 파일을 컨테이너에 복사하는 레이어&lt;/p&gt;
&lt;/div&gt;
&lt;h1&gt;Docker Image -&amp;gt; Container 순서&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;346&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qOeG5/btsCDem5VeW/urk1Z9rppi2AQxoFjK3vO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qOeG5/btsCDem5VeW/urk1Z9rppi2AQxoFjK3vO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qOeG5/btsCDem5VeW/urk1Z9rppi2AQxoFjK3vO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqOeG5%2FbtsCDem5VeW%2Furk1Z9rppi2AQxoFjK3vO0%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;846&quot; height=&quot;346&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;346&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Dokcerfile 작성&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;319&quot; data-origin-height=&quot;221&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vf1Fz/btsCDfmlRE7/qc5IkbIKGiyB6KxakKWmB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vf1Fz/btsCDfmlRE7/qc5IkbIKGiyB6KxakKWmB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vf1Fz/btsCDfmlRE7/qc5IkbIKGiyB6KxakKWmB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVf1Fz%2FbtsCDfmlRE7%2Fqc5IkbIKGiyB6KxakKWmB0%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;319&quot; height=&quot;221&quot; data-origin-width=&quot;319&quot; data-origin-height=&quot;221&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Docker build (&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;이미지 생성)&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1703660234534&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; % docker build -t dockertest:latest .
[+] Building 0.0s (5/5) FINISHED                                                                                   docker:desktop-linux
 =&amp;gt; [internal] load .dockerignore                                                                                                  0.0s
 =&amp;gt; =&amp;gt; transferring context: 2B                                                                                                    0.0s
 =&amp;gt; [internal] load build definition from dockerfile                                                                               0.0s
 =&amp;gt; =&amp;gt; transferring dockerfile: 283B                                                                                               0.0s
 =&amp;gt; [internal] load metadata for docker.io/library/alpine:latest                                                                   0.0s
 =&amp;gt; CACHED [1/1] FROM docker.io/library/alpine                                                                                     0.0s
 =&amp;gt; exporting to image                                                                                                             0.0s
 =&amp;gt; =&amp;gt; exporting layers                                                                                                            0.0s
 =&amp;gt; =&amp;gt; writing image sha256:0f2a33b340f39b5580c51c388037157d5596c555aade4f9eb6c9c99e3cb47eac                                       0.0s
 =&amp;gt; =&amp;gt; naming to docker.io/library/dockertest:latest                                                                               0.0s

What's Next?
  View a summary of image vulnerabilities and recommendations &amp;rarr; docker scout quickview&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;&quot;docker build -t dockertest:latest .&quot; -t는 태그로 &lt;span style=&quot;background-color: #c1bef9;&quot;&gt;dockertest&lt;/span&gt; 라는 이름으로 tag하겠다는 뜻이다. 맨마지막에 . 을 찍는걸 실수하지 말자 -&amp;gt; 나중에 해당 이미지를 run돌릴때 tag로 호출하면 편하기 때문&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;1129&quot; data-origin-height=&quot;569&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WFOYe/btsCBMkqtSu/M1bsGtFanyBerbsGahnkB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WFOYe/btsCBMkqtSu/M1bsGtFanyBerbsGahnkB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WFOYe/btsCBMkqtSu/M1bsGtFanyBerbsGahnkB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWFOYe%2FbtsCBMkqtSu%2FM1bsGtFanyBerbsGahnkB1%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;1129&quot; height=&quot;569&quot; data-origin-width=&quot;1129&quot; data-origin-height=&quot;569&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 아래와 같이 출력하게 하고싶다면 &lt;span style=&quot;color: #111827; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;DOCKER_BUILDKIT=0&lt;/span&gt; 로 비활성화를 한다.&lt;/span&gt;&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #111827; text-align: start;&quot;&gt;BuildKit : Docker 18.09버전부터 새로운 이미지 빌드 시스템 도입&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1703661834738&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;% DOCKER_BUILDKIT=0 docker build .
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
            BuildKit is currently disabled; enable it by removing the DOCKER_BUILDKIT=0
            environment-variable.

Sending build context to Docker daemon  6.144kB
Step 1/2 : FROM alpine
 ---&amp;gt; 1dc785547989
Step 2/2 : CMD [&quot;echo&quot;,&quot;hello&quot;]
 ---&amp;gt; Running in cb16c68a65a8
Removing intermediate container cb16c68a65a8
 ---&amp;gt; ce94e625b2bf
Successfully built ce94e625b2bf

What's Next?
  View a summary of image vulnerabilities and recommendations &amp;rarr; docker scout quickview&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/du69W4/btsCDgMhzMF/OqFjpspDjTxYDid9Gx2suk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/du69W4/btsCDgMhzMF/OqFjpspDjTxYDid9Gx2suk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/du69W4/btsCDgMhzMF/OqFjpspDjTxYDid9Gx2suk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdu69W4%2FbtsCDgMhzMF%2FOqFjpspDjTxYDid9Gx2suk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;734&quot; height=&quot;362&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1968&quot; data-origin-height=&quot;988&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d2dPS9/btsCBNwPhVk/sDU1jbHWCsUMJfgkD0Kzuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d2dPS9/btsCBNwPhVk/sDU1jbHWCsUMJfgkD0Kzuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d2dPS9/btsCBNwPhVk/sDU1jbHWCsUMJfgkD0Kzuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd2dPS9%2FbtsCBNwPhVk%2FsDU1jbHWCsUMJfgkD0Kzuk%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;1968&quot; height=&quot;988&quot; data-origin-width=&quot;1968&quot; data-origin-height=&quot;988&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1802&quot; data-origin-height=&quot;936&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpfqtU/btsCKP8bdlp/u8N44xejboWaQRslWKfSG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpfqtU/btsCKP8bdlp/u8N44xejboWaQRslWKfSG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpfqtU/btsCKP8bdlp/u8N44xejboWaQRslWKfSG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpfqtU%2FbtsCKP8bdlp%2Fu8N44xejboWaQRslWKfSG0%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;1802&quot; height=&quot;936&quot; data-origin-width=&quot;1802&quot; data-origin-height=&quot;936&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Docker run (이미지로 부터 컨테이너 생성 및 실행&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;) : 이때 컨테이너는 이미지의 상태를 실시간으로 반영&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1703661911761&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;% docker run dockertest:latest
hello&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 백그라운드로 실행하고 싶다면&amp;nbsp; -d&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;background-color: #f7f7f7; border: #c1c1c1 1px solid; padding: 10px;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;질문1. 왜 백그라운드로 컨테이너를 실행하려는 걸까?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;멀티테스킹 : 터미널,콘솔이 해당 컨테이너에 계속 연결되어 있지 않아도 된다 -&amp;gt; 사용자가 다른 작업 계속 할 수 있다.&lt;/li&gt;
&lt;li&gt;서비스 유지 : 웹서버,DB와 같이 중단없이 백그라운드에서 계속 실행이 필요한 서비스,application의 경우 지속적으로 서비스 제공 가능&lt;/li&gt;
&lt;li&gt;환경 분리 : 사용자의 현재 터미널,콘솔세션이 독립적으로 실행되어 다중 작업 수행이 가능하다.(동일한 터미널이나 다른 터미널에서 다른 작업 가능)&lt;/li&gt;
&lt;li&gt;로그관리 : 백그라운드 모드의 경우 Docker의 로깅시스템으로 직접 관리됨 (docker logs)&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1703661971071&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;% docker run -d dockertest:latest    
5182fd2a20064c2319e222657e648e1a5f616818cbcf164498a3b3baf2ec8b0d&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;4. Container 확인&lt;/h3&gt;
&lt;pre id=&quot;code_1703663034891&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;% docker ps -a 
CONTAINER ID   IMAGE               COMMAND                  CREATED              STATUS                          PORTS      NAMES
5182fd2a2006   dockertest:latest   &quot;echo hello&quot;             About a minute ago   Exited (0) About a minute ago              competent_davinci&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;h1&gt;도커 이미지 명령어&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;images list 확인&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ docker ls

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              0d9c6c5575f5        4 days ago          126MB
ubuntu              18.04               47b199b0cb85        2 weeks ago         64.2MB&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;registry에서 image pull하기&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;$ docker pull alpine:3.11

3.11: Pulling from library/alpine
Digest: sha256:9f11a34ef1c67e073069f13b09fb76dc8f1a16f7067eebafc68a5049bb0a072f
Status: Downloaded newer image for alpine:3.11&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Docker에서 image 삭제하기&lt;/h2&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;$ docker rmi &amp;lt;image_id&amp;gt;

Untagged: &amp;lt;image_id&amp;gt;
Deleted: sha256:&amp;lt;image_id&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Docker Host의 image VS Registry의 image&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker Host image&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-level=&quot;1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬에 저장되며, 해당 시스템에서 직접 사용가능&lt;/p&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Registry image&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-level=&quot;1&quot;&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;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고자료&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.docker.com/get-started/overview/&quot;&gt;https://docs.docker.com/get-started/overview/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/what-is-docker-images/&quot;&gt;https://www.geeksforgeeks.org/what-is-docker-images/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://peterica.tistory.com/212&quot;&gt;https://peterica.tistory.com/212&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hoon93.tistory.com/48&quot;&gt;https://hoon93.tistory.com/48&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@bsjp400/Docker-Docker-file%EB%A1%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%83%9D%EC%84%B1%EB%B0%A9%EB%B2%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@bsjp400/Docker-Docker-file%EB%A1%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%83%9D%EC%84%B1%EB%B0%A9%EB%B2%95&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;따라하며 배우는 도커와 CI환경 강의&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@bsjp400/Docker-Docker-file%EB%A1%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%83%9D%EC%84%B1%EB%B0%A9%EB%B2%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@bsjp400/Docker-Docker-file%EB%A1%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%83%9D%EC%84%B1%EB%B0%A9%EB%B2%95&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DOCKER</category>
      <author>PeonyF</author>
      <guid isPermaLink="true">https://peonyf.tistory.com/202</guid>
      <comments>https://peonyf.tistory.com/entry/Docker-Docker-Image#entry202comment</comments>
      <pubDate>Tue, 26 Dec 2023 19:01:44 +0900</pubDate>
    </item>
    <item>
      <title>[Docker]  Docker Container1 - 기본 개념</title>
      <link>https://peonyf.tistory.com/entry/Docker-%08Docker-Container</link>
      <description>&lt;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;Containers vs. VMs&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1225&quot; data-origin-height=&quot;501&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/83941/btsCsoijJ3C/k1F8xofg5K5R6h56YprMSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/83941/btsCsoijJ3C/k1F8xofg5K5R6h56YprMSK/img.png&quot; data-alt=&quot;containers vs. VMs&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/83941/btsCsoijJ3C/k1F8xofg5K5R6h56YprMSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F83941%2FbtsCsoijJ3C%2Fk1F8xofg5K5R6h56YprMSK%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;1225&quot; height=&quot;501&quot; data-origin-width=&quot;1225&quot; data-origin-height=&quot;501&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;containers vs. VMs&lt;/figcaption&gt;
&lt;/figure&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;blockquote data-ke-style=&quot;style2&quot;&gt;A container is an isolated&amp;nbsp;environment for&amp;nbsp;your&amp;nbsp;code.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker Image를 통해 application을 실행하기 위해 모든것(코드,런타임,시스템 도구,시스템 라이브러리 설정등)을 포함하고 있는 기술인데, 이 기술을 통해 어느 환경에서나 일관된 방식으로 실행할수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너가 &lt;s&gt;사용자가 가지고 있는 OS나 파일에 대한 정보 없이&lt;/s&gt; Docker Desktop에 제공하는 환경에서 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bN3SZ1/btsCKSQEIAl/WyZHvmBYCTUtVVmO16zLQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bN3SZ1/btsCKSQEIAl/WyZHvmBYCTUtVVmO16zLQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bN3SZ1/btsCKSQEIAl/WyZHvmBYCTUtVVmO16zLQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbN3SZ1%2FbtsCKSQEIAl%2FWyZHvmBYCTUtVVmO16zLQk%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;1000&quot; height=&quot;362&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;어떻게 컨테이너가 독립적으로 가능할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker Desktop을 사용하여 컨테이너를 관리, 탐색하고 컨테이너가 기본 OS를 포함한 실행하려는 코드를 위한 &lt;span style=&quot;color: #8a3db6;&quot;&gt;모든것&lt;/span&gt;을 가지고 있기때문에 가능하다.&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;background-color: #f7f7f7; border: #c1c1c1 1px solid; padding: 10px;&quot;&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;질문1. 컨테이너가 코드를 위한 모든, 어떤것을 가지고 있을까?&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 런타임 환경,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;실제 실행하려는 애플리케이션의 코드,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;애플리케이션의 실행에 필요한 외부 라이브러리와 의존성,시스템 도구 및 유틸리티, 설정파일 및 환경변수 ,&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;기본 운영체제(&lt;span style=&quot;color: #8a3db6;&quot;&gt;단 전체이미지가 아님&lt;/span&gt;) 등과 같은 구성요소들이 함께 작동해서 컨테이너가 어떤환경에서도 일관된 방식으로 애플리케이션을 실행할 수 있게 한다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;질문 1-1. 컨테이너가 기본 운영체제를 가지고 있는데 왜 전체 이미지가 아닐까?&lt;/h4&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;containers do not contain operating system images. This makes them more lightweight and portable, with significantly less overhead&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;컨테이너와 가상머신의 주된 차이점 중 하나. 전체이미지를 가지고 있지않아 컨테이너는 가볍고,이식성이 높다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;질문 1-1-1. 그러면 어떻게 운영체제를 가져올까?&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;docker hub에서 필요한 base operating system를 image로 전달해서 전체 OS 이미지가 필요없다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;질문 1-1-1-1.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;docker hub가 뭐지?&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;Docker 이미지를 저장하고 공유하는 서비스, 기본 OS 레이어와 필요한 소프트웨어,라이브러리를 포함하고 있어 컨테이너가 독립적으로 실행 가능.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;ex. ubuntu image : Ubuntu OS 기반의 컨테이너를 만들고 싶다면, Docker Hub에서 Ubuntu 이미지를 가져와 사용&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; 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;960&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cu1agP/btsCyx8T0sk/EqgPcx9pqxJvxBkZJRkfq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cu1agP/btsCyx8T0sk/EqgPcx9pqxJvxBkZJRkfq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cu1agP/btsCyx8T0sk/EqgPcx9pqxJvxBkZJRkfq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcu1agP%2FbtsCyx8T0sk%2FEqgPcx9pqxJvxBkZJRkfq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;720&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;760&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;295&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDkqk5/btsCzQz2rFu/iAiPk0XODrlKxuiBK2Fsk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDkqk5/btsCzQz2rFu/iAiPk0XODrlKxuiBK2Fsk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDkqk5/btsCzQz2rFu/iAiPk0XODrlKxuiBK2Fsk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDkqk5%2FbtsCzQz2rFu%2FiAiPk0XODrlKxuiBK2Fsk1%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;700&quot; height=&quot;295&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;295&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;720&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Linux Containers rely on control groupsopen_in_new which not only track groups of processes, but also expose metrics about CPU, memory, and block I/O usage. You can access those metrics and obtain network usage metrics as well. This is relevant for &quot;pure&quot; LXC containers, as well as for Docker containers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스에서 쓰이는 Cgroup(control groups)와 namespace로 격리시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;namespace를 통해 프로세스들을 구별, Cgroup을 통해 이 프로세스들의 사용가능한 자원을 제한한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Cgroup&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스와 스레드를 그룹화하여, 그 그룹안에 존재하는 프로세스와 스레드에 대한 관리를 수행-&amp;gt; 리소스 사용량을 제한,격리가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cgroup는 계층 구조를 사용하여 프로세스를 그룹화 하여 관리할수있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;247&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJMHVP/btsCIHV8qS3/rsbWByadDIcudJYjOvCcrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJMHVP/btsCIHV8qS3/rsbWByadDIcudJYjOvCcrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJMHVP/btsCIHV8qS3/rsbWByadDIcudJYjOvCcrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJMHVP%2FbtsCIHV8qS3%2FrsbWByadDIcudJYjOvCcrk%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;247&quot; data-origin-width=&quot;458&quot; data-origin-height=&quot;247&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;458&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/civ7NY/btsCyMrndnQ/EmRc38ZiajUgRbQeC70Qe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/civ7NY/btsCyMrndnQ/EmRc38ZiajUgRbQeC70Qe0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/civ7NY/btsCyMrndnQ/EmRc38ZiajUgRbQeC70Qe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fciv7NY%2FbtsCyMrndnQ%2FEmRc38ZiajUgRbQeC70Qe0%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;700&quot; height=&quot;398&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;720&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div data-width-type=&quot;pixel&quot; data-width=&quot;595&quot; data-layout=&quot;center&quot; data-node-type=&quot;mediaSingle&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;269&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qRlTT/btsCzq2D1Vb/qLIQM39L8kjykNeRzpiZX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qRlTT/btsCzq2D1Vb/qLIQM39L8kjykNeRzpiZX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qRlTT/btsCzq2D1Vb/qLIQM39L8kjykNeRzpiZX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqRlTT%2FbtsCzq2D1Vb%2FqLIQM39L8kjykNeRzpiZX1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;595&quot; height=&quot;269&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;269&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Cgroup의 주요 서브 시스템&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-table-width=&quot;760&quot; data-table-local-id=&quot;001c506a-77f0-42af-be78-d292ce8eaa29&quot; data-autosize=&quot;false&quot; data-layout=&quot;default&quot; data-number-column=&quot;false&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;cpu&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td data-colwidth=&quot;663&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;cpu 사용량을 제한&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;cpuact&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td data-colwidth=&quot;663&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;cpu 사용량 통계 정보를 제공&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;cpuset&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td data-colwidth=&quot;663&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;cpu나 메모리 배치를 제어&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;memory&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td data-colwidth=&quot;663&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;메모리나 스왑 사용량을 제한&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;devices&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td data-colwidth=&quot;663&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;디바이스에 대한 엑세스 허가/거부&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;freezer&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td data-colwidth=&quot;663&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;그룹에 속한 프로세스 정지/재개&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;net_cls&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td data-colwidth=&quot;663&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;네트워크 제어 태그를 부가&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;blkio&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td data-colwidth=&quot;663&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;블록 디바이스 입출력량을 제어&lt;/span&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;블록 디바이스란? 데이터를 고정된 크기로 관리하는(각 블록은 고유한 주소가 있음) 저장장치(HDD,SSD,USB)&lt;/li&gt;
&lt;li&gt;블록 디바이스 I/O란? 데이터를 저장/검색하는 방법으로 블록 디바이스를 통한 입력/출력 작업&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Cgroup 특징&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;cgroup은 부모 자식 관계에서는 자식이 부모의 제한을 물려받기 때문에 자식은 부모 그룹의 제한을 초과하여 할당할 수 없어 중요한 프로세스라도 영향을 받지 않는다. &amp;rarr; 시스템의 중요 부분에 대한 과도한 자원 사용 방지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;namespace 격리로 보안과 안정성,자원관리 가능
&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;질문1. 프로세스 그룹이 실제 시스템에서 어떻게 활용되는건가?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;위에 그림과 같이 웹 서버 그룹(Nginx와 같은 웹서버 실행시), DB서버 그룹(MySQL등 사용시), 백그라운드 작업 그룹(시스템에서 정기적 실행되는 백업 스크립트,로그작업시),사용자별,application 별 그룹 등&lt;/li&gt;
&lt;li&gt;실행되는 application의 요구사항,시스템의 전체 리소스,성능,보안 요구사항등의 여러요소들로 Cgroup의 프로세스 그룹화가 결정됨. 따라서 각 시스템과 application마다 Cgroup의 설정이 다르다.&lt;/li&gt;
&lt;li&gt;ex. Java 계산기 프로그램 : 독립적으로 실행되는 간단한 애플리케이션은 Docker의 기본 설정만으로 가능&lt;/li&gt;
&lt;li&gt;스프링 프레임워크를 사용하여 구현된 웹 서버를 실행할 경우, 웹 서버 그룹이나 데이터베이스 서버 그룹 같은 cgroup 설정이 필요할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;우선 순위 설정 : 다른 Cgroup의 프로세스들이 사용하는 자원들에 비해 얼마나 자원을 사용할 수 있는지 설정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자원제한 변경 : 시스템에서 특정 Cgroup에 할당된 CPU나 메모리와 같은 자원제한을 동적으로 조정가능(시스템 부하가 높을떄, 특정 서비스의 리소스 사용량을 제한)&lt;/li&gt;
&lt;li&gt;Cgroup의 cpu 서브시스템을 사용: 특정 Cgroup에 대한 CPU시간의 비율 조절 가능(두개의 Cgroup이 있을때 한 그룹에 CPU 시간을 더 많이 할당시 CPU 가중치를 더 높게 할당-&amp;gt; CPU를 더 많이 사용할수있게 우선순위 간접 설정)&lt;/li&gt;
&lt;li&gt;Cgroup의 memory 서브시스템을 사용: 특정 Cgroup의 메모리 사용량을 제한 &amp;rarr; 메모리를 과도하게 사용 방지&lt;/li&gt;
&lt;li&gt;Cgroup의  blkio 서브시스템을 사용: 특저&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;감시/관리 : Cgroup 단위에서 자원을 얼마나 사용하고 있는지 모니터링/ 모든 프로세스들의 상태를 한번에 변경 가능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일시 중지/재개 : 시스템의 유지보수,업데이트 중 특정 application을 일시 중지 시키고 작업이 끝난 후 재개시 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Cgroup의 자원 제한으로 인한 이점:&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다중 사용자 환경 : 시스템에 여러 사용자,서비스 동시 실행시 한 사용자/서비스가 시스템의 모든 자원 독점 방지&lt;/li&gt;
&lt;li&gt;서비스 품질 보장 : 중요 application에 충분한 자원이 할당되도록 하여 성능 보장&lt;/li&gt;
&lt;li&gt;시스템 안정성 : 시스템의 전체 자원을 적절히 제어해, 과부하 상태로 인한 시스템 불안정성 방지&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Namespace&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스 격리(= 프로세스 구별)로 이로인해 충돌가능성을 줄이고, 쉽게 참조할수 있게한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(PID를 통해 각 컨테이너에 대해 독립적인 프로세스 번호 공간을 제공)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker는 컨테이너라는 독립된 환경을 만들고, 그 컨테이너를 구획화하여 application의 실행환경을 만든다.&lt;/li&gt;
&lt;li&gt;여기서 이 컨테이너를 구획화하는 기술을 linux의 namespace라는 기능을 사용한다.&lt;/li&gt;
&lt;li&gt;각 namespace는 특정한 시스템 리소스나 속성을 격리하기때문에 프로세스는 여러 namespace에 걸쳐 다양하게 격리되고 환경을 가질 수 있다.(namespace는 프로세스가 필요에 따라 다른 격리된 환경에서 작동할 수 있게 함)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex. IPC Namespace에서 &lt;span&gt;pid:1&lt;/span&gt;과 &lt;span&gt;pid:2&lt;/span&gt;가 서로 통신&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UTS Namespace에서 &lt;span&gt;pid:1&lt;/span&gt;과 &lt;span&gt;pid:3&lt;/span&gt;가 함께 격리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Namespace의 주요 서브 시스템&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;463&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/53J9k/btsCDeUvAlg/4N0XWbn7BqaK5WKIifmu9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/53J9k/btsCDeUvAlg/4N0XWbn7BqaK5WKIifmu9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/53J9k/btsCDeUvAlg/4N0XWbn7BqaK5WKIifmu9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F53J9k%2FbtsCDeUvAlg%2F4N0XWbn7BqaK5WKIifmu9k%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;643&quot; height=&quot;463&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;463&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 483px;&quot; border=&quot;1&quot; data-table-width=&quot;760&quot; data-table-local-id=&quot;d2e90377-b235-4814-b6e8-23fa41416a8a&quot; data-autosize=&quot;false&quot; data-layout=&quot;default&quot; data-number-column=&quot;false&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 187px;&quot;&gt;
&lt;td style=&quot;width: 8.02326%; height: 187px;&quot; data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt; mnt&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 91.9767%; height: 187px;&quot; data-colwidth=&quot;663&quot;&gt;&lt;span&gt;파일 시스템 마운트 : Host 파일 시스템에 독립적인 파일 시스템 마운트&lt;/span&gt;&lt;br /&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;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;monut namespace는 마운트 조작을 하면 namespace안에 격리된 파일 시스템 트리를 만든다.&lt;/li&gt;
&lt;li&gt;namespace 안에서 수행된 마운트는 호스트 OS,다른 namespace에서는 엑세스 할 수 없게 되어있다. (각 application이 자신만의 파일시스템 구조를 유지 및 은닉,변경 못하도록 하기 위함)&lt;/li&gt;
&lt;/ol&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 8.02326%; height: 20px;&quot; data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;pid&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 91.9767%; height: 20px;&quot; data-colwidth=&quot;663&quot;&gt;&lt;span&gt;각 프로세스에 할당된 고유한 ID : 독립적인 프로세스 공간 할당&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 96px;&quot;&gt;
&lt;td style=&quot;width: 8.02326%; height: 96px;&quot; data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;net&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 91.9767%; height: 96px;&quot; data-colwidth=&quot;663&quot;&gt;&lt;span&gt;네트워크 디바이스, IP 주소, 포트 번호, 라우팅 테이블, 필터링 테이블 등과 같은 네트워크 리소스를 격리된 namespace마다 독립적으로 가질 수 있다&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&amp;rarr; namespace간의 충돌 방지(중복 포트 바인딩 등)&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 8.02326%; height: 40px;&quot; data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;ipc&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 91.9767%; height: 40px;&quot; data-colwidth=&quot;663&quot;&gt;&lt;span&gt;IPC는 프로세스간의 통신 오브젝트(공유메모리, 세마포어,메세지큐)로 통신(IPC) 오브젝트를 namespace별로 독립적으로 가질 수 있다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 56px;&quot;&gt;
&lt;td style=&quot;width: 8.02326%; height: 56px;&quot; data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;uts&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 91.9767%; height: 56px;&quot; data-colwidth=&quot;663&quot;&gt;&lt;span&gt; 자신만의 호스트이름과 네트워크 도메인 이름을 가질 수 있음&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 74px;&quot;&gt;
&lt;td style=&quot;width: 8.02326%; height: 74px;&quot; data-colwidth=&quot;95&quot;&gt;
&lt;div data-align=&quot;center&quot;&gt;&lt;span&gt;user&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 91.9767%; height: 74px;&quot; data-colwidth=&quot;663&quot;&gt;&lt;span&gt;독립적인 사용자,그룹ID 할당&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mnt(mount)&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;595&quot; data-origin-height=&quot;414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L4NyC/btsCEHWB0rI/IiznrNi0Ms0KO2FgYUCPi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L4NyC/btsCEHWB0rI/IiznrNi0Ms0KO2FgYUCPi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L4NyC/btsCEHWB0rI/IiznrNi0Ms0KO2FgYUCPi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL4NyC%2FbtsCEHWB0rI%2FIiznrNi0Ms0KO2FgYUCPi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;595&quot; height=&quot;414&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;414&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;pid&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;595&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDvraL/btsCBJ8hsQT/4Bkyyfl4Jw4iZPbmk6ZATK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDvraL/btsCBJ8hsQT/4Bkyyfl4Jw4iZPbmk6ZATK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDvraL/btsCBJ8hsQT/4Bkyyfl4Jw4iZPbmk6ZATK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDvraL%2FbtsCBJ8hsQT%2F4Bkyyfl4Jw4iZPbmk6ZATK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;595&quot; height=&quot;380&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;380&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;net&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;595&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/69Wzd/btsCG1N5lOy/KAuE7CoKOeoCfROfqasVWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/69Wzd/btsCG1N5lOy/KAuE7CoKOeoCfROfqasVWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/69Wzd/btsCG1N5lOy/KAuE7CoKOeoCfROfqasVWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F69Wzd%2FbtsCG1N5lOy%2FKAuE7CoKOeoCfROfqasVWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;595&quot; height=&quot;380&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;380&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;ipc&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;595&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJqWoc/btsCKsdmpa0/nHPkkRe4jLmOfKKNpXbLEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJqWoc/btsCKsdmpa0/nHPkkRe4jLmOfKKNpXbLEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJqWoc/btsCKsdmpa0/nHPkkRe4jLmOfKKNpXbLEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJqWoc%2FbtsCKsdmpa0%2FnHPkkRe4jLmOfKKNpXbLEK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;595&quot; height=&quot;380&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;380&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;uts&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;595&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zqwkg/btsCy5xxofL/rzKVikMO6Xlnp1fj2Fpe21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zqwkg/btsCy5xxofL/rzKVikMO6Xlnp1fj2Fpe21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zqwkg/btsCy5xxofL/rzKVikMO6Xlnp1fj2Fpe21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzqwkg%2FbtsCy5xxofL%2FrzKVikMO6Xlnp1fj2Fpe21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;595&quot; height=&quot;380&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;380&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;user&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;595&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdMASv/btsCIHPoZJJ/hIfhx0O85ztzZtfkCPgSe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdMASv/btsCIHPoZJJ/hIfhx0O85ztzZtfkCPgSe1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdMASv/btsCIHPoZJJ/hIfhx0O85ztzZtfkCPgSe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdMASv%2FbtsCIHPoZJJ%2FhIfhx0O85ztzZtfkCPgSe1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;595&quot; height=&quot;506&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;506&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Namespace의 독립적으로 작동하여 얻는 이점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너가 각각 독립적인 파일 시스템을 가져(자신만의 파일 시스템 마운트 관리) 컨테이너가 별도의 서버인것처럼 작동할 수 있게 해줌&lt;/li&gt;
&lt;li&gt;특정상황에 일부 namespace가 불필요한 경우(컨테이너가 networking을 전혀 사용하지 않아 NET namespace가 필요없는 경우, 컨테이너가 단일 프로세스로 실행되어 호스트 이름,도메인 이름에 의존하지 않아 UTS namespace가 필요없는 경우 등) Docker 실행 명령어나 Dockerfile, Docker Compose 파일에서 특정 옵션을 통해 namespace사용을 커스텀 할 수 있다. (단 격리 수준이 낮아짐)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker 명령어 사용(1. NET namespace 사용X시, 2. IPC namespace 사용X시)&lt;/li&gt;
&lt;li&gt;Docker Compose 사용시(3. 해당 서비스가 호스트의 NET namespace를 사용하도록 지정함, 별도의 NET namespace 생성X)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;docker run --net=host myimage&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;docker run --ipc=host myimage&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;version: '3'
services:
  app:
    image: myappimage
    network_mode: &quot;host&quot;  # 사용할 네트워크 모드 지정&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;질문1. 격리 수준이 낮아진다는건 무슨 의미인가?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너가 실행되는 환경과 다른 환경 사이의 경계가 옅어져 아래와 같은 문제 발생&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;보안위험이 증가 : 만약 , 호스트의 네트워크 네임스페이스로 통일될경우 모든 네트워크 인터페이스에 직접 엑세스 할수있음&lt;/li&gt;
&lt;li&gt;리소스 충돌 : 여러 컨테이너나 호스트 시스템이 동일한 리소스를 동시에 사용시 충돌 발생&lt;/li&gt;
&lt;li&gt;관리 복잡성 : 시스템의 어떤부분이 문제를 일으키는지 파악하기 어려움&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-pm-slice=&quot;1 1 []&quot;&gt;컨테이너 작동과정&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;752&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bb9OFc/btsCIFd56Yu/EE8AdAN6N3DBXisX9xEw21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bb9OFc/btsCIFd56Yu/EE8AdAN6N3DBXisX9xEw21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bb9OFc/btsCIFd56Yu/EE8AdAN6N3DBXisX9xEw21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbb9OFc%2FbtsCIFd56Yu%2FEE8AdAN6N3DBXisX9xEw21%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;300&quot; height=&quot;752&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;752&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;Step1. 두프로그램이 각각 다른 Python 버전을 원하는 상황&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot;&gt;Chrome -&amp;gt; python2, NodeJs -&amp;gt; python3&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot;&gt;해당 하드디스크는 Python2만 접근가능하고 동시에 두개의 동일한 Python 설치 X&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;418&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpt31H/btsCP3R2ALw/muIXWr5plaEKVRrOwiC1xK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpt31H/btsCP3R2ALw/muIXWr5plaEKVRrOwiC1xK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpt31H/btsCP3R2ALw/muIXWr5plaEKVRrOwiC1xK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbpt31H%2FbtsCP3R2ALw%2FmuIXWr5plaEKVRrOwiC1xK%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;450&quot; height=&quot;269&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;418&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;Step2. OS의 Namespace 기능 사용&lt;/h3&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;color: #374151; text-align: start;&quot;&gt;Namespace를 통해 커널은 Chrome과 NodeJS 각각이 필요로 하는 다른 버전의 Python에 접근 가능&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;&lt;/span&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;프로그램이 요청을 합니다 (시스템 콜 발행) : &lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot;&gt;Chrome -&amp;gt; python2, NodeJs -&amp;gt; python3 필요 요청&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;커널이 요청을 받아 처리 : 어느 프로그램으로 부터 온 요청(시스템콜) 확인&amp;nbsp;&lt;/li&gt;
&lt;li&gt;커널이 리소스 접근을 적절한 곳으로 연결해줍니다 (리디렉션) &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;커널은 Chrome이 요청한 Python 버전 2를 사용할 수 있는 하드 드라이브의 특정 영역(세그먼트)으로 연결&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2992&quot; data-origin-height=&quot;1516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b56vb6/btsCP5h2Fq3/ZaKqdTQLckGtfElO8S4hg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b56vb6/btsCP5h2Fq3/ZaKqdTQLckGtfElO8S4hg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b56vb6/btsCP5h2Fq3/ZaKqdTQLckGtfElO8S4hg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb56vb6%2FbtsCP5h2Fq3%2FZaKqdTQLckGtfElO8S4hg0%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;600&quot; height=&quot;1516&quot; data-origin-width=&quot;2992&quot; data-origin-height=&quot;1516&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;Step2. Cgroup 기능 사용&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Cgroup은 &lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot;&gt;특정 프로세스가 사용할 수 있는 리소스 수를 제한하는 데 사용한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot;&gt;커널은 들어오는 시스템 호출을 보고 이를 하드 드라이브의 특정 부분(RAM CPU 또는 필요한 다른 부분)으로 보낸다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;color: #000000; text-align: left;&quot; 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;2430&quot; data-origin-height=&quot;1092&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vDtLY/btsCG4ysXBn/IyFaF7a4kPUzfCTkBl8LV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vDtLY/btsCG4ysXBn/IyFaF7a4kPUzfCTkBl8LV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vDtLY/btsCG4ysXBn/IyFaF7a4kPUzfCTkBl8LV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvDtLY%2FbtsCG4ysXBn%2FIyFaF7a4kPUzfCTkBl8LV1%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;2430&quot; height=&quot;1092&quot; data-origin-width=&quot;2430&quot; data-origin-height=&quot;1092&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;Step3. 해당 Container의 Image스냅샷 사용 및 Container 시작&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;namespace와 Cgroup을 통해 하드디스크의 일부분을 격리해 하드디스크의 작은 부분을 컨테이너만 사용하도록 한다.&lt;/li&gt;
&lt;li&gt;이미지의 파일 스냅샷을 컨테이너 공간(hard drive segment)에 배치한다. -&amp;gt; 해당 컨테이너 실행시 필요한 파일,설정 포함&lt;/li&gt;
&lt;li&gt;구체적인 리소스 그룹 구성 : 세그멘트에 &lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;Chrome과 Python만 설치됨 -&amp;gt; 컨테이너가 사용할 독립된 환경 형성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;컨테이너 시작 명령 실행 -&amp;gt; Chrome 사용&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kjzps/btsCy5j9k8q/WofBMIJ9QNk4mVE0ezWX90/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kjzps/btsCy5j9k8q/WofBMIJ9QNk4mVE0ezWX90/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kjzps/btsCy5j9k8q/WofBMIJ9QNk4mVE0ezWX90/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKjzps%2FbtsCy5j9k8q%2FWofBMIJ9QNk4mVE0ezWX90%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;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;컨테이너 특징&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너는 이미지 Layer에 읽기/쓰기 Layer를 추가하는 것으로 생성/실행된다. 따라서 여러개의 컨테이너를 생성해도 최소한의 용량만 사용되며 바뀐부분은 읽기/쓰기 Layer에 적는다.&lt;/li&gt;
&lt;li&gt;컨테이너는 종료되었다고 메모리에서 삭제되지 않고 남아있다. (삭제하려면 명시적으로 삭제해야 한다.) 즉 종료가 되어도 컨테이너, 읽기/쓰기 Layer 또한 그래도 존재하기 때문에 다시 시작할 수 있다.&lt;/li&gt;
&lt;li&gt;컨테이너 삭제란 컨테이너에서 생성한 파일이 사라진다는 것이다. ex. DB 삭제 &amp;rarr; DB내의 모든 데이터 삭제&lt;/li&gt;
&lt;li&gt;한 서버는 여러개의 컨테이너를 가질 수 있으며 컨테이너는 각각 독립적으로 실행된다.&lt;/li&gt;
&lt;li&gt;컨테이너는 kernel공간과 host os자원을 공유한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-level=&quot;1&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div data-level=&quot;1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;txc-textbox&quot; style=&quot;background-color: #f7f7f7; border: #c1c1c1 1px solid; padding: 10px;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. host system 의 host 이름이 host-system&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 두 개의 컨테이너(Container A와 Container B)를 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Container A에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;hostname&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;명령어를 실행하면 &quot;container-A&quot;라는 결과를 얻는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Container B에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;hostname&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;명령어를 실행하면 &quot;container-B&quot;라는 결과를 얻는다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 각 컨테이너가 UTS 네임스페이스를 통해 자신만의 호스트 이름을 가짐을 의미&lt;/p&gt;
&lt;div style=&quot;color: #333333; text-align: start;&quot; data-level=&quot;1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(컨테이너가 host-system의 커널을 공유해도 UTS namespace는 컨테이너마다 독립적으로 관리함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;docker run -d --name container-A --hostname=container-A ubuntu sleep 3600&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-d&lt;/span&gt; : 컨테이너를 백그라운드에서 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;--hostname&lt;/span&gt;: 컨테이너의 호스트 이름을 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ubuntu&lt;/span&gt; : 사용할 베이스 이미지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;sleep 3600&lt;/span&gt;: 컨에이너가 바로 종료하지 않고 1시간 대기&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;% docker run -d --name container-A --hostname=container-A ubuntu sleep 3600
5e4b162f3357bfe120ac07a4aff4faacb69de9449b062fcef22051088d90fc34
% docker run -d --name container-B --hostname=container-B ubuntu sleep 3600
21ebf4feb110f799c2457926c6897ad1049cc58b133db86be6d7ef2c8580e871&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;% docker ps
CONTAINER ID   IMAGE     COMMAND                   CREATED          STATUS          PORTS      NAMES
21ebf4feb110   ubuntu    &quot;sleep 3600&quot;              2 seconds ago    Up 1 second                container-B
5e4b162f3357   ubuntu    &quot;sleep 3600&quot;              20 seconds ago   Up 19 seconds              container-A
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-pm-slice=&quot;1 1 []&quot;&gt;Docker Containter lifecycle&lt;/h2&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1XZKf/btsCALr49z8/JoTlRtu7CKCCHAI1QzKEP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1XZKf/btsCALr49z8/JoTlRtu7CKCCHAI1QzKEP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1XZKf/btsCALr49z8/JoTlRtu7CKCCHAI1QzKEP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1XZKf%2FbtsCALr49z8%2FJoTlRtu7CKCCHAI1QzKEP1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;664&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;664&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size23&quot;&gt;컨테이너 생성&amp;nbsp;&lt;/h3&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;docker create --name my-hello-container hello-world&lt;/span&gt;&lt;/p&gt;
&lt;p data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;(녹색 박스) : 파일 스냅샷을 하드디스크에 넣어줌.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;% docker create --name test-hello-container hello-world
e521b1dd85b5ca60119ac0479c38a473c7ecbc95a54a5f2709b6b74470f46bf1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컨테이너 실행 run(새로운 컨테이너를 이미지로부터 실행: create+start)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;docker run my-hello-container&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;(파란색 박스) : 이미지에서 받아온 시작 명령어 실행.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;868&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OY4nq/btsCMq7ytmQ/JPwheHmhQ3Cjj4hK3TycMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OY4nq/btsCMq7ytmQ/JPwheHmhQ3Cjj4hK3TycMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OY4nq/btsCMq7ytmQ/JPwheHmhQ3Cjj4hK3TycMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOY4nq%2FbtsCMq7ytmQ%2FJPwheHmhQ3Cjj4hK3TycMk%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;1236&quot; height=&quot;868&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;868&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컨테이너 실행 start (이미 생성된 컨테이너를 시작하려면)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;docker start my-hello-container&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;% docker start -a test-hello-container

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the &quot;hello-world&quot; image from the Docker Hub.
    (arm64v8)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/&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;컨테이너 일시중지 (더 긴 실행 시간이 필요한 ubuntu 이미지로 변경)&lt;/h3&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;$ docker run -d --name ubuntu-container ubuntu sleep 3600
$ docker pause ubuntu-container

0b2a913ec95bdee0b285f603e53dc7800feaf75a877fbc849216a737b3623e70&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컨테이너 중지 stop&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;docker stop ubuntu-container&lt;/span&gt; 그동안 하던 작업들을 완료하고 컨테이너를 중지 시킨다.&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;$ docker stop ubuntu-container
ubuntu-container&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;컨테이너 중지 kill&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;docker kill ubuntu-container&lt;/span&gt; 어떠한 것도 기다리지 않고 바로 컨테이너를 중지&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;$ docker kill ubuntu-container
ubuntu-container&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컨테이너 재개 :&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;docker unpause ubuntu-container&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컨테이너 삭제(&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;실행중인 컨테이너는 반드시 중지해야 삭제가 가능하다)&lt;/span&gt;:&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;docker rm ubuntu-container&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;axapta&quot;&gt;&lt;code&gt;$ docker rm ubuntu-container
ubuntu-container&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&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;span&gt;docker rm 'docker ps -a -q'&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;전체 컨테이너 확인 : &lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;docker ps -a&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;도커 실행 중 명령어 전달하기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;도커 실행중에 명령어를 사용하기 위해서는 컨테이너 안에서 실행을 해야 하기에 컨테이너 아이디를 적어줘야 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;(docker ps로 확인)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;ex) 터미널 A에서 docker run redis 실행후 터미널 B에서 redis-cli 명령어를 쓰는경우 정상적으로 작동하지 않음.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;=&amp;gt; 터미널 A는 redis 컨테이너를 실행되고 있는 중에 터미널 B의 명령어는 redis 컨테이너 밖이기 때문에 명령어가 작동하지 않으므로 다음과 같아야 한다&lt;/span&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1703638833497&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# docker exec &amp;lt;컨테이너 아이디&amp;gt; &amp;lt;명령어&amp;gt;
docker exec cbba6354bdad ls&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;실행중인 컨테이너의 터미널로 접근하기&lt;/h3&gt;
&lt;pre id=&quot;code_1703639048840&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# docker exec -it &amp;lt;컨테이너 아이디&amp;gt; &amp;lt;sh/bash/zsh 등등..&amp;gt;
docker exec -it a096f4bf67f6 redis-cli&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span&gt;docker ps 명령어를 통해 container id를 확인 후 &amp;lt;컨테이너 아이디&amp;gt;에 적어준다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;-it 을 붙여줘야 명령어를 실행한 후 계속 명령어를 적을 수 있다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;실행중인 컨테이너에 여러번 명령어를 실행해야 할 경우 5번에 설명한것과 같이 &quot;docker exec -it &amp;lt;컨테이너 아이디&amp;gt; &amp;lt;명령어&amp;gt;&quot; 방식으로 계속 입력하기에는 비효율적임&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;실행중인 컨테이니의 터미널로 접근도 가능하다. -&amp;gt; 마지막의 명령어를 redis-cli와 같은것 대신 sh로 바꿔준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1703642232845&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; % docker ps                      
CONTAINER ID   IMAGE     COMMAND                   CREATED         STATUS         PORTS      NAMES
ea45b6de24b8   alpine    &quot;ping localhost&quot;          4 seconds ago   Up 3 seconds              flamboyant_knuth
 % docker exec -it ea45b6de24b8 ls
bin    dev    etc    home   lib    media  mnt    opt    proc   root   run    sbin   srv    sys    tmp    usr    var
% docker exec -it ea45b6de24b8 echo &quot;hello&quot;
hello

'''
위와 같이 매번 &quot;docker exec -it ea45b6de24b8&quot; 를 입력하는게 번거로우므로 
맨 마지막에 sh를 붙여 쉘환경으로 진입하여 반복 코드 없앰
터미널 종료 방법은  control + D
'''

 % docker exec -it ea45b6de24b8 sh          
/ # ls
bin    dev    etc    home   lib    media  mnt    opt    proc   root   run    sbin   srv    sys    tmp    usr    var
/ # echo hello
hello
/ #&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-pm-slice=&quot;1 1 []&quot; data-ke-size=&quot;size26&quot;&gt;Docker Container VS Docker Image&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 82px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 54.6512%; height: 10px; text-align: center;&quot;&gt;&lt;b&gt;Docker Container&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.3488%; height: 10px; text-align: center;&quot;&gt;&lt;b&gt;Docker Image&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 54.6512%; height: 18px;&quot;&gt; Docker Image를 기반으로 실행되는 각각 컨테이너가 그 이미지의 &amp;ldquo;실행버전&amp;rdquo; (인스턴스화)&lt;br /&gt;(이미지의 상태를 복제하여 실행함)&lt;/td&gt;
&lt;td style=&quot;width: 45.3488%; height: 18px;&quot;&gt;Docker Image는 Docker Container의 소스 코드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 54.6512%; height: 18px;&quot;&gt; Docker Image는 Docker Container의 전제조건&lt;br /&gt;(Dockerfile로부터 이미지를 빌드한 이미지를 기반으로 컨테이너를 실행)&lt;/td&gt;
&lt;td style=&quot;width: 45.3488%; height: 18px;&quot;&gt;Dockerfile은  Docker Image의 필수 구성요소&lt;br /&gt;(Dockerfile로부터 이미지를 빌드)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 54.6512%; height: 18px;&quot;&gt;Docker Container는 유저들끼리 공유할수 없다.&lt;br /&gt;(컨테이너는 실행 중인 이미지 인스턴스여서 동적이고 일시적이라 공유X)&lt;/td&gt;
&lt;td style=&quot;width: 45.3488%; height: 18px;&quot;&gt;Docker Image는 Docker Hub를 통해 사용자간에 공유 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 54.6512%; height: 18px;&quot;&gt;Docker Container는 컨테이너가 실행중일때 사용자가 컨테이너 내부에 들어가 바로 수정 가능하다.&lt;br /&gt;(docker exec 명령어 사용)&lt;/td&gt;
&lt;td style=&quot;width: 45.3488%; height: 18px;&quot;&gt;Docker Image를 수정하기 위해서는 Dockerfile를 수정해야한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;a href=&quot;https://docs.docker.com/guides/walkthroughs/what-is-a-container/#what-is-a-container&quot;&gt;https://docs.docker.com/guides/walkthroughs/what-is-a-container/#what-is-a-container&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.docker.com/config/containers/runmetrics/&quot;&gt;https://docs.docker.com/config/containers/runmetrics/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.netapp.com/devops-solutions/what-are-containers/&quot;&gt;https://www.netapp.com/devops-solutions/what-are-containers/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.linkedin.com/pulse/cgroups-docker-pavan-shukla/&quot;&gt;https://www.linkedin.com/pulse/cgroups-docker-pavan-shukla/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://codu.tistory.com/39&quot;&gt;https://codu.tistory.com/39&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://inma.tistory.com/148&quot;&gt;https://inma.tistory.com/148&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.docker.com/build/building/multi-stage/&quot;&gt;https://docs.docker.com/build/building/multi-stage/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.cherryservers.com/blog/docker-multistage-build&quot;&gt;https://www.cherryservers.com/blog/docker-multistage-build&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.annotation-ai.com/python-docker-img-optimization/&quot;&gt;https://blog.annotation-ai.com/python-docker-img-optimization/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.vantage-ai.com/vantage101/chapter-9-docker&quot;&gt;https://www.vantage-ai.com/vantage101/chapter-9-docker&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kimjingo.tistory.com/38&quot;&gt;https://kimjingo.tistory.com/38&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/echo-devblog/%EB%8F%84%EC%BB%A4%EB%A5%BC-%EB%8F%84%EC%9E%85%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-1-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EA%B8%B0%EC%88%A0-%EC%9B%90%EB%A6%AC-90a28c14024e&quot;&gt;https://medium.com/echo-devblog/%EB%8F%84%EC%BB%A4%EB%A5%BC-%EB%8F%84%EC%9E%85%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-1-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EA%B8%B0%EC%88%A0-%EC%9B%90%EB%A6%AC-90a28c14024e&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/51765555/what-namespaces-are-shared-among-containers-in-a-kubernetes-pod&quot;&gt;https://stackoverflow.com/questions/51765555/what-namespaces-are-shared-among-containers-in-a-kubernetes-pod&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://platform.sh/blog/the-container-is-a-lie/&quot;&gt;https://platform.sh/blog/the-container-is-a-lie/&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hoon93.tistory.com/48&quot;&gt;https://hoon93.tistory.com/48&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://www.google.com/url?sa=i&amp;amp;url=https%3A%2F%2Fwww.brendangregg.com%2FSlides%2FDockerCon2017_performance_analysis%2F&amp;amp;psig=AOvVaw3ArdNcd-J8utcvTx964unc&amp;amp;ust=1703658733500000&amp;amp;source=images&amp;amp;cd=vfe&amp;amp;opi=89978449&amp;amp;ved=0CBMQjhxqFwoTCLi43r69rIMDFQAAAAAdAAAAABA1&quot;&gt;DockerCon2017_performance_analysis.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/what-is-docker-images/&quot;&gt;https://www.geeksforgeeks.org/what-is-docker-images/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;따라하며 배우는 도커와 CI환경 강의&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;a href=&quot;https://medium.com/tech-learn-share/how-docker-containers-work-462ce3a5ea0f&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/tech-learn-share/how-docker-containers-work-462ce3a5ea0f&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DOCKER</category>
      <author>PeonyF</author>
      <guid isPermaLink="true">https://peonyf.tistory.com/200</guid>
      <comments>https://peonyf.tistory.com/entry/Docker-%08Docker-Container#entry200comment</comments>
      <pubDate>Thu, 21 Dec 2023 18:10:31 +0900</pubDate>
    </item>
  </channel>
</rss>