<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jhanggun_kim.log</title>
        <link>https://velog.io/</link>
        <description>Make impacts!</description>
        <lastBuildDate>Mon, 25 Dec 2023 05:23:36 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jhanggun_kim.log</title>
            <url>https://velog.velcdn.com/images/jhanggun_kim/profile/13ee1311-66c4-4e39-871e-44b26870f815/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jhanggun_kim.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jhanggun_kim" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[TIL 231225 - Python 장식자로 정책과 메커니즘을 나눈다?]]></title>
            <link>https://velog.io/@jhanggun_kim/TIL-231225</link>
            <guid>https://velog.io/@jhanggun_kim/TIL-231225</guid>
            <pubDate>Mon, 25 Dec 2023 05:23:36 GMT</pubDate>
            <description><![CDATA[<p>눈물의 1225 TIL... 그래도 배운 게 있으면 됐다 ㅋㅋㅋ</p>
<p>DB를 쓰는 코드를 짤 때, 에러를 생각해야 한다.
DB는 멈출 수도 있고 네트워크가 끊길 수도 있고 인풋 데이터 사이 충돌이 생길 수도 있고 별 에러가 나타날 수 있다.
이러한 코드를 돌릴 때 에러가 있을 수 없다고 생각하는 것은 그냥 생각이 짧고 경험이 없다는 것을 보여 주는 것이다.
비즈니스 코드를 짤 때는 에러가 난다고 해서 프로세스가 멈추면 안 된다.
몇 번의 retry 로직이 있어야 한다.</p>
<p>그러나 좀 더 생각해 보자.
그렇다면 DB를 쓰는 함수마다 로직을 짜는 것은 말이 안 된다.
Python의 backoff 라이브러리를 써 보자.
이 라이브러리는 retry 로직을 쉽게 정의할 수 있게 하고, temp 에러를 프로세싱하기 쉽게 만들어 준다.</p>
<p>이런 식으로 정책과 메커니즘을 나누는 것은 아주 중요하다.
정책: 무엇을 할 것인가.
메커니즘: &#39;어떻게&#39; 할 것인가.
정책은 환경에 따라 아주 쉽게 바뀔 수 있기 때문에,
정책과 메커니즘을 나누지 않았다면 정책이 바뀔 때마다 더 많은 코드를 지우고 써야 한다.</p>
<p>하나의 함수 안에 정책과 메커니즘이 모두 들어 있지 않게 해 보자.
하나의 정책은 하나의 함수에.
하나의 메커니즘은 하나의 함수에.</p>
<p>함수는 짧을수록 한 눈에 이 함수가 무슨 일을 하는지 알기가 쉬워진다는 것을 잊지 말자.</p>
<hr>

<p>이 밖에도 많은 라이브러리들이 어떠한 메커니즘을 장식자로 이쁘게 만들어 두었을 것이다.</p>
<p>장식자를 적극적으로 찾고 써 보자.</p>
<p>예를 들면...</p>
<ul>
<li>함수의 아웃풋을 캐시에 담아 두는 functools.lru_cache: 함수의 인수와 그 아웃풋은 dict에 쌓이게 된다. 따라서 이 장식자를 쓰는 함수의 인수는 넘버, strings, tuples처럼 dict&#39;s key로 쓰일 수 있어야 한다. 아래 my_fibo 함수에서 캐시를 쓸 때와 안 쓸 때 시간이 많이 다를 것이다.<pre><code># https://kimjingo.tistory.com/169
</code></pre></li>
</ul>
<p>from time import time
from functools import lru_cache</p>
<p>@lru_cache(maxsize=32)
def my_fibo(n):
    if n == 0:
        return 0
    elif n == 1 or n == 2:
        return 1
    else:
        return my_fibo(n - 1) + my_fibo(n - 2)</p>
<p>start_time = time()
output = my_fibo(40)
end_time = time() - start_time
print(output, end_time)</p>
<p>```</p>
<ul>
<li>다음으로, CLI를 더 쉽게 만들어 주는 Click 라이브러리가 있다. <a href="https://monkey3199.github.io/python/library/2019/06/29/python-library-click.html">여기</a>를 봐 보자.</li>
<li>함수에게 시간 리밋을 줄 수 있는 timeout_decorator 라이브러리도 잘 쓰면 아주 좋겠다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Basics of Git]]></title>
            <link>https://velog.io/@jhanggun_kim/git-basic</link>
            <guid>https://velog.io/@jhanggun_kim/git-basic</guid>
            <pubDate>Sat, 05 Aug 2023 12:55:49 GMT</pubDate>
            <description><![CDATA[<p>소프트웨어 <u>버전 매니지먼트</u> 시스템 가운데 하나.</p>
<p>파일마다 리비전 히스토리를 쉽게 볼 수 있어서 파일 버전끼리 견주거나 파일의 어떤 버전으로 코드를 쉽게 되돌릴 수 있습니다.</p>
<hr>

<center><h2>Repositories</h2></center>

<p>GIT 소프트웨어에는 repository들이 있고,</p>
<p>리포지터리에 들어 있는 파일마다 리비전 히스토리를 가지고 있습니다.</p>
<p>Repository에는 2가지 갈래가 있습니다.</p>
<ul>
<li>리모트 리포지터리: 서버에 두고 쓰는 리포지터리로, 여러 사람이 함께 공유하기 위한 리포지터리.</li>
<li>로컬 리포지터리: 내 PC에서 쓰기 위한 리포지터리.</li>
</ul>
<p>여러분의 로컬 리포지터리에서 코드를 업데이트하다가</p>
<p>공유를 해야 할 때 리모트 리포지터리에 업로드를 하면 됩니다.</p>
<p>거꾸로 다른 사람이 업로드한 파일을 로컬 리포지터리로 가져올 수 있습니다.</p>
<p>컴퓨터에 로컬 리포지터리를 만드는 방법은 2가지가 있습니다.</p>
<ol>
<li>새 리포지터리를 만드는 것.</li>
<li>리모트 리포지터리를 본떠서 로컬 리포지터리를 만드는 것. 이때 리모트 리포지터리의 리비전 히스토리도 같이 가져옴.</li>
</ol>
<p>2를 위해 아래 커맨드를 쓰면 됩니다.</p>
<pre><code>git clone ${URI}</code></pre><hr>

<center><h2>Commits</h2></center>

<p>파일, 폴더를 새로 만들었거나 업데이트 콘텐츠를 리포지터리에 올리려면 먼저 commit을 해 줘야 합니다.</p>
<p>Commit을 하면, 바로 앞선 commit부터 현재까지의 모든 리비전 히스토리를 가지고 있는 새 commit이 만들어집니다.</p>
<p>Commits에는 알파벳, 넘버로 이루어진 40자리의 유니크한 이름이 붙습니다.</p>
<p>Commit마다 메시지가 반드시 있어야 합니다.</p>
<p>메시지는 심플하고 알기 쉽게 만드는 게 좋을 겁니다.</p>
<pre><code>git commit -m ${message}</code></pre><hr>

<center><h2>워크 트리와 인덱스</h2></center>

<p>Git에서는 폴더를 <u>워크 트리</u>라고 합니다.</p>
<p>여러분은 워크 트리에 있는 어떤 파일들을 업데이트하겠죠?</p>
<p>그리고 이 업데이트한 파일들을 로컬 리포지터리에 업로드하기 위해 commit을 해야 합니다.</p>
<p>그런데 이 commit이라는 게 업데이트 콘텐츠들을 바로 로컬 리포지터리에 올리는 게 아닙니다.</p>
<p>워크 트리와 로컬 리포지터리 사이에는 <u>인덱스</u>라는 게 있습니다.</p>
<p>Commit은 인덱스에 스테이지 되어 있는 콘텐츠들을 로컬 리포지터리에 올리는 겁니다.</p>
<p>그래서 여러분은 인덱스에 먼저 스테이지시켜 주어야 하는 거예요.</p>
<ol>
<li>워크 트리에서 로컬 리포지터리에 올리고 싶은 파일들을 인덱스에 스테이지.</li>
<li>인덱스에서 로컬 리포지터리로 commit.</li>
</ol>
<p>워크 트리에서 인덱스에 스테이지를 하는 커맨드는 아래와 같습니다.</p>
<pre><code>git add ${FILEPATH1} (${FILEPATH2})</code></pre><p>워크 트리에서 파일 또는 폴더를 지우면서 인덱스에 스테이지를 하는 커맨드는 아래와 같습니다.</p>
<pre><code>git rm ${FILEPATH1} (${FILEPATH2})    &lt;-- 파일
git rm -r ${FILEPATH1} (${FILEPATH2}) &lt;-- 폴더와 그 아래의 모든 폴더, 파일까지</code></pre><p>조금 더 몇 가지 커맨드들을 알아봅시다.</p>
<p>Commit 할 때 a 옵션을 붙이면 새로 만들어진 파일 말고, 업데이트된 파일들을 찾아 인덱스에 스테이지시킵니다.</p>
<p>그 다음에 commit까지 하나의 커맨드로 이루어지는 거예요.</p>
<pre><code>git commit -a -m ${message}</code></pre><p>리모트 리포지터리에 있는 리비전 히스토리를 팀에 공유를 해야 할 때가 있겠죠.</p>
<pre><code>git push (origin master)</code></pre><p>git push = git push origin master입니다.</p>
<p>여기에서 말하는 origin은 리모트 리포지터리를 가리킵니다.</p>
<p>리모트 리포지터리에 있는 master 브랜치에 업로드하겠다는 얘기가 되겠죠.</p>
<p>또한 u 옵션을 붙이면 origin, master 파트를 fix,</p>
<p>git push 커맨드만 쳐도 git push origin master 커맨드로 알아듣게 됩니다.</p>
<pre><code>git push -u origin master</code></pre><p>거꾸로 리모트 리포지터리에서 업데이트된 리비전 히스토리를 가져오고 싶다면?</p>
<pre><code>git pull origin svc</code></pre><p>그냥 git pull 커맨드를 쓸 수도 있지만 지금은 이렇게 써서</p>
<p>리모트 리포지터리에 있는 svc 브랜치의 리비전 히스토리를 가져오는 걸로 알고 씁시다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[컨테이너 커뮤니케이션]]></title>
            <link>https://velog.io/@jhanggun_kim/%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EC%BB%A4%EB%AE%A4%EB%8B%88%EC%BC%80%EC%9D%B4%EC%85%98</link>
            <guid>https://velog.io/@jhanggun_kim/%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EC%BB%A4%EB%AE%A4%EB%8B%88%EC%BC%80%EC%9D%B4%EC%85%98</guid>
            <pubDate>Sat, 24 Dec 2022 06:42:36 GMT</pubDate>
            <description><![CDATA[<h1 id="컨테이너와-www">컨테이너와 WWW</h1>
<p>먼저 컨테이너에 있는 애플리케이션에서 HTTP 리퀘스트를</p>
<p>다른 웹 사이트 또는 웹 API로 보낼 수 있습니다.</p>
<p>컨테이너는 디폴트로 WWW에 리퀘스트를 보낼 수 있습니다.</p>
<hr>

<h1 id="컨테이너와-호스트">컨테이너와 호스트</h1>
<p>컨테이너에 있는 애플리케이션에서</p>
<p>컨테이너 바깥에 있는 호스트 머신이나 그 머신에 있는 DB 등과 커뮤니케이션을 하려는 케이스가 있을 겁니다.</p>
<p>이 케이스에서는 Docker가 만들어 놓은 유니크한 도메인, <strong>host.docker.internal</strong>을 쓰면 됩니다.</p>
<hr>

<h1 id="컨테이너와-컨테이너">컨테이너와 컨테이너</h1>
<p>컨테이너에서 다른 컨테이너와 커뮤니케이션을 하려 합니다.</p>
<p>예를 들어 B 컨테이너에 DB가 있다고 해 보죠.</p>
<p>하나의 컨테이너에는 하나의 기능만 있는 것이 옳기 때문에</p>
<p>어느 정도의 사이즈가 있는 애플리케이션이라면</p>
<p>하나의 컨테이너로는 모자랍니다.</p>
<p>어쨌든 다른 컨테이너와 커뮤니케이션을 하기 위해선 커뮤니케이션이 다 그렇듯이 IP 어드레스를 알고 있어야 합니다.</p>
<pre><code>docker container inspect CONTAINER_NAME</code></pre><p>이 커맨드에 대한 아웃풋에서 NetworkSettings에 IPAddress 값이 있습니다.</p>
<p>하지만.. IPAddress 값을 그대로 가져다 쓰는 것은 아름답지 않습니다.</p>
<p>이 어드레스는 바뀔 수 있는 것이니까요.</p>
<hr>

<h1 id="docker-네트워크">Docker 네트워크</h1>
<p>Docker로 컨테이너 네트워크라는 것을 만들 수 있습니다.</p>
<p>그냥 네트워크라고 부르기도 합니다.</p>
<p>먼저 네트워크를 만들어야 합니다.</p>
<pre><code>docker network create NETWORK_NAME</code></pre><p>이제 docker run 커맨드를 돌릴 때 위에서 만든 네트워크를 붙일 수 있습니다.</p>
<pre><code>docker run --network NETWORK_NAME</code></pre><p>애플리케이션 코드에는 앞서 썼던 IP 어드레스도 아니고, host.docker.internal도 아니고, 뭘 써야 할까요?</p>
<p>컨테이너 이름을 써 주면 네트워크에서 이를 알 수 있습니다.</p>
<p>물론 반드시 같은 네트워크에 있는 컨테이너 이름이어야 하고요..!</p>
<p>모든 컨테이너를 하나의 네트워크에 집어 넣을 수 있습니다.</p>
<p>네트워크를 하는 일에 따라 묶을 수 있도 있겠죠!?</p>
<hr>

<h1 id="네트워크-드라이버">네트워크 드라이버</h1>
<p>Docker 네트워크는 여러 드라이버를 가지고 있습니다.</p>
<pre><code>docker network create --driver bridge NETWORK_NAME</code></pre><p>웬만하면 디폴트 값인 bridge 드라이버를 쓰시게 될 겁니다.</p>
<p>하지만 이러한 값들이 있다는 걸 알고 있으면 좋겠죠?</p>
<ul>
<li>host: 호스트 시스템을 네트워크 안에 집어 넣습니다.</li>
<li>overlay</li>
<li>macvlan: 컨테이너에 custom MAC 어드레스를 정할 수 있습니다.</li>
<li>none: 네트워크를 끕니다.</li>
<li>서드파티 플러그인</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[데이터, 볼륨]]></title>
            <link>https://velog.io/@jhanggun_kim/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B3%BC%EB%A5%A8</link>
            <guid>https://velog.io/@jhanggun_kim/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B3%BC%EB%A5%A8</guid>
            <pubDate>Sat, 24 Dec 2022 04:28:02 GMT</pubDate>
            <description><![CDATA[<p>Docker에서 쓸 수 있는 데이터에는 여러 가지가 있습니다.</p>
<ol>
<li>애플리케이션<ul>
<li>소스 코드와 이를 돌리기 위한 여러 엘리먼트들.</li>
<li>이미지 빌드할 때 복제되며, 바꿀 수 없습니다.</li>
<li>Read-only 데이터이며, 이미지에 담겨 있습니다.</li>
</ul>
</li>
<li>Temporarily 앱 데이터<ul>
<li>애플리케이션이 돌아갈 때 생길 수 있는 데이터들.</li>
<li>예를 들면 유저의 인풋 값.</li>
<li><u>메모리 또는 임시 파일 등</u>에 담기게 될 것입니다.</li>
<li><strong>컨테이너를 끝낼 때 없어져도 되는 데이터들</strong>.</li>
<li>읽고 쓸 수 있는 데이터로, 컨테이너가 가지고 있습니다.</li>
</ul>
</li>
<li>Permanent 앱 데이터<ul>
<li>애플리케이션이 돌아갈 때 생길 수 있는 데이터들.</li>
<li>하지만 <strong>데이터가 남아 있어야</strong> 합니다.</li>
<li>예를 들면 유저 어카운트 데이터.</li>
<li><u>파일 또는 DB 등</u>에 담기게 될 것입니다.</li>
<li>읽고 쓸 수 있는 데이터로 컨테이너가 가지고 있지만, 볼륨의 도움을 받습니다.</li>
</ul>
</li>
</ol>
<hr>

<h1 id="볼륨">볼륨</h1>
<p>볼륨에 대해서 알아봅시다.</p>
<p>볼륨은 <u>호스트 머신의 폴더</u>를 말합니다.</p>
<p>호스트 머신에 있는 어떤 폴더가 컨테이너 안의 어떤 폴더로 <span style="color: red"><strong>매핑</strong></span>되는 것입니다.</p>
<p>매핑되어 있는 두 폴더 가운데 하나가 바뀌면 다른 폴더도 똑같이 바뀝니다.</p>
<p>이를 위해 Dockerfile에 VOLUMN 커맨드를 쓰시면 됩니다.</p>
<pre><code>VOLUMN [&quot;/data&quot;]</code></pre><p>위 path는 컨테이너 안의 path입니다.</p>
<p><span style="color: grey">※ Docker는 컨테이너의 파일 시스템 안에서 파일을 움직일 수 없게 해 두었습니다. 컨테이너의 안, 또는 바깥으로의 디렉션으로만 움직일 수 있게 되어 있습니다. 컨테이너의 파일 시스템 안에서 파일을 움직이게 하고 싶다면, 복사하고 나서 파일을 지우는 것으로 해 주시면 됩니다.</span></p>
<p><span style="color: grey">※ 볼륨이 호스트 머신의 어디에 있는지 Docker에서는 여러분이 알기를 바라지 않습니다. 혹시나 안다고 하더라도 그 폴더에 대해 어떤 일을 하지 마세요.</span></p>
<hr>

<h1 id="볼륨-타입">볼륨 타입</h1>
<p>볼륨에는 2가지 타입이 있습니다.</p>
<p>Anonymous 볼륨, 그리고 named 볼륨입니다.</p>
<p>Anonymous 볼륨은 그 컨테이너에 붙어 있는 볼륨입니다.</p>
<p>컨테이너를 --rm 옵션으로 시작 또는 돌렸을 때,</p>
<p>컨테이너가 할 일을 마치고 사라지면 anonymous 볼륨 또한 같이 사라집니다.</p>
<p>다만 --rm 옵션이 없었다면 그 컨테이너가 멈추었더라도 링크만 끊어질 뿐 anonymous 볼륨은 살아 있습니다.</p>
<p>이러한 볼륨은 쓸 수가 없으니 docker volumn rm VOL_NAME 또는 docker volumn prune 커맨드로 지워 주세요.</p>
<p>위에서 Dockerfile에 VOLUMN 커맨드를 쓰라고 했는데, 이는 anonymous 볼륨을 만듭니다.</p>
<p>Named 볼륨을 만들고 싶다면 아래와 같이 docker run에 -v 옵션을 넣으세요.</p>
<pre><code>docker run -v name:path</code></pre><p><u>Named 볼륨은 컨테이너와 상관없이 살아 있기 때문에</p>
<p>여러 컨테이너가 쓸 수 있습니다</u>.</p>
<hr>

<h1 id="바인드-마운트">바인드 마운트</h1>
<p>컨테이너 안에서 소스 코드를 바꾼다고 하더라도 그것에는 어떠한 임팩트도 없죠.</p>
<p>애플리케이션은 이미지에 있으며, 이것은 읽을 수만 있는 것이니까요.</p>
<p>하지만 개발을 하다 보면 소스 코드를 조금씩 바꾸면서 애플리케이션이 뜻대로 잘 돌아가는지 체크하고 싶을 때가 많잖아요?</p>
<p>Docker에 이를 위한 어떤 기능이 있지 않을까요..?</p>
<p>네, <span style="color: red">바인드 마운트</span>가 있습니다.</p>
<p>이것은 볼륨과 비슷하지만, 다른 게 하나 있습니다.</p>
<p>우리는 볼륨이 호스트의 어디에 있는지 알지 못하지만 바인드 마운트는 <span style="color: red">알 수 있습니다</span>.</p>
<p>바인드 마운트를 정할 때 우리는 호스트의 어떤 패스와 매핑을 시킬 것인지 함께 정합니다.</p>
<pre><code>docker run -v ABS_PATH_OF_HOST:PATH</code></pre><p>어떠한 패스든지 바인드 마운트를 만들 수 있는 것은 아닙니다.</p>
<p>Docker의 <strong>Preferences/Resources/FILE SHARING</strong> 메뉴에 listing되어 있는 폴더 패스 안에 있어야 합니다.</p>
<p>그렇지 않다면 FILE SHARING에 새 패스를 넣어 주시고요.</p>
<hr>

<h1 id="prioritize">Prioritize</h1>
<p>여기서 우리는 컨테이너가 볼륨과 바인드 마운트와 어떻게 커뮤니케이션을 하는지 알아봐야 합니다.</p>
<p>컨테이너의 어떤 패스에 볼륨 또는 바인드 마운트를 이을지 정할 수 있죠?</p>
<p>그러면 컨테이너를 돌리거나 시작시킬 때, 볼륨 또는 바인드 마운트에 있는 폴더 또는 파일들을 컨테이너 패스에 덮어쓰게 됩니다.</p>
<p>또한 Docker는 언제나 컨테이너를 시작하거나 돌릴 때 붙을 모든 볼륨을 체크하는데, </p>
<p>붙일 볼륨이 많아 유저가 잘못해서 패스가 겹치는 등의 크래시가 있다면</p>
<p><u>패스가 더 긴</u>, <u>그러니까 더 아래 레벨</u>이랑 매핑될 볼륨만 받아들이게 됩니다.</p>
<p>Anonymous 볼륨을 이럴 때 쓸 수 있습니다.</p>
<p>docker run -v PATH로도 anonymous 볼륨을 만들 수 있는데요.</p>
<pre><code>docker run -v &quot;C:\Users\user\Desktop\Project\PROJECT_NAME:/app&quot; -v /app/node_modules ...</code></pre><p>위 코드에서 바인드 마운트랑 anonymous 볼륨의 패스가 겹치는데,</p>
<p>anonymous 볼륨의 패스가 더 깊기 때문에</p>
<p>app의 node_modules 디렉터리에 대해선 anonymous 볼륨이랑 이어지고 나머지 app 디렉터리는 바인드 마운트랑 이어지게 되는 것이죠.</p>
<p>마땅하게도 anonymous 볼륨에는 뭐가 없을 거기 때문에 /app/node_modules에는 이미지에서의 /app/node_modules 폴더 및 파일들이 있을 것입니다.</p>
<p>보통 이런 dependency들은 이미지 레벨에서 깔도록 하니까요.</p>
<p>볼륨 또는 바인드 마운트를 만들 때 패스 크래시로 인해서 이미지에서 빌드한 이 dependency들이 지워지지 않도록 할 수 있는 것입니다.</p>
<p>아 물론 이 케이스는 우리의 로컬 애플리케이션 디렉터리에 dependency들이 없을 때를 얘기하는 거고요.</p>
<hr>

<p>윈도즈에서 WSL2를 쓰는 케이스라면 꼭 알아 두어야 할 게 있습니다.</p>
<p>소스 코드를 바꿀 때마다 dev 서버가 스스로 다시 시작을 하게 해 두었더라도,</p>
<p>WSL2를 쓰고 있다면 잘 안 될 수 있습니다.</p>
<p>이는 소스 코드 및 프로젝트 파일들을 리눅스에 여러분이 두어야 하기 때문인데요,</p>
<p>2가지 방법이 있겠네요.</p>
<p>첫 번째 방법은 윈도즈 패스를 WSL2에 마운트 하는 것입니다.</p>
<p>이를 위해 <a href="https://devblogs.microsoft.com/commandline/access-linux-filesystems-in-windows-and-wsl-2/">링크</a>를 남겨 두겠습니다.</p>
<p>두 번째 방법은 WSL2를 윈도즈의 디폴트 터미널로 쓰는 겁니다.</p>
<hr>

<h1 id="read-only-볼륨">Read-only 볼륨</h1>
<p>볼륨은 디폴트로 읽기, 쓰기를 할 수 있으며</p>
<p>이는 컨테이너가 볼륨에서 데이터를 읽기도 하고, 볼륨에 데이터를 쓰기도 할 수 있음을 뜻합니다.</p>
<p>그런데 읽기만 될 수 있게 정할 수 있습니다.</p>
<pre><code>docker run -v &quot;C:\Users\user\Desktop\Project\PROJECT_NAME:/app:ro&quot;</code></pre><p>위 코드와 같이 볼륨 또는 바인드 마운트의 패스 뒤에 <strong>:ro</strong>를 붙이면 됩니다.</p>
<p>이제 Docker는 이 패스 및 아래 패스들에 대해 쓰기를 할 수 없게 됩니다.</p>
<p>물론 호스트 머신 파일 시스템에는 쓰기를 할 수 있고,</p>
<p>컨테이너와, 컨테이너에서 돌아가는 애플리케이션에만 임팩트가 갑니다.</p>
<p>이와 더불어 위와 같이 app 패스에 대해 read-only 세팅을 했다 하더라도</p>
<p>app/feedback 패스에 대해 볼륨 또는 바인드 마운트가 생긴다면 feedback에 대해서는 읽기, 쓰기를 할 수 있게 되고요.</p>
<hr>

<p>볼륨은 Docker에서 매니지먼트하지만, 볼륨 안을 들여다보거나 Docker가 볼륨에 뭘했는지 살펴볼 수 있습니다.</p>
<pre><code>docker volume --help</code></pre><p>위 커맨드를 돌려 보면 여러 가지 기능들이 있다는 걸 알 수 있을 겁니다.</p>
<pre><code>docker volumn inspect VOLUMN_NAME</code></pre><p>위 커맨드로 볼륨의 마운트 포인트도 알 수 있습니다.</p>
<p>하지만 이 마운트 포인트 패스가 호스트 머신 파일 시스템이랑은 좀 달라요.</p>
<p>Docker가 여러분의 호스트 머신 파일 시스템에 작은 VM 하나를 두었고, 그 안의 패스를 가리키는 거거든요.</p>
<hr>

<h1 id="dockerignore">.dockerignore</h1>
<p>.dockerignore 파일을 만들어 COPY 하고 싶지 않은 디렉터리 또는 파일을 정할 수 있습니다.</p>
<p>Dockerfile에 따로 어떤 커맨드를 주지 않아도 돼요.</p>
<p>Docker에서 .dockerignore 파일을 찾으면 알아서 이 안에 있는 디렉터리 또는 파일들은 COPY 하지 않습니다.</p>
<hr>

<h1 id="arg-env">ARG, ENV</h1>
<p>Dockerfile에서 쓸 수 있는 ARG, ENV 커맨드에 대해 알아봅시다.</p>
<p>ARG 커맨드는 Dockerfile에서만 쓸 수 있는 변수를 만듭니다.</p>
<p>만들어 둔 변수는 docker build 커맨드에 --build-arg 옵션을 붙여 쓸 수 있습니다.</p>
<p>ENV 커맨드는 Dockerfile뿐만 아니라 컨테이너에서 돌아가고 있는 애플리케이션 코드에서도 쓸 수 있는 변수를 만듭니다.</p>
<p>Dockerfile에 아래와 같이 쓸 수 있어요.</p>
<pre><code># PORT가 변수 이름이고 80은 디폴트 값.
ENV PORT 80</code></pre><p>docker run 커맨드에 --e(nv) 옵션을 붙여 env들에 대한 값을 붙이면 됩니다.</p>
<p>바란다면 ENV만을 위한 파일을 만들어 둘 수도 있을 겁니다.</p>
<p>흔히 .env 파일을 만들곤 합니다.</p>
<p>그리고 run 커맨드에 --env-file 옵션을 주면 돼요.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[이미지와 컨테이너]]></title>
            <link>https://velog.io/@jhanggun_kim/%EC%9D%B4%EB%AF%B8%EC%A7%80%EC%99%80-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</link>
            <guid>https://velog.io/@jhanggun_kim/%EC%9D%B4%EB%AF%B8%EC%A7%80%EC%99%80-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</guid>
            <pubDate>Mon, 05 Dec 2022 09:00:45 GMT</pubDate>
            <description><![CDATA[<p>이미지는 코드와 코드를 돌리기 위한 여러 툴을 가지고 있습니다.</p>
<p>컨테이너는 이미지로 만들어진 인스턴스라 보시면 됩니다.</p>
<p>정리하자면 이미지는 클래스, 컨테이너는 인스턴스와 매치가 됩니다.</p>
<hr>

<p>이미지를 가져오는 방법을 알아보겠습니다.</p>
<p>Docker Hub에 많은 이미지들이 있어요.</p>
<p>예를 들어 Node.JS 이미지는 아래 커맨드로 가져올 수 있습니다.</p>
<pre><code>docker pull node</code></pre><p>run 커맨드를 쓰면 Docker Hub에서 이미지의 newest 버전을 다운로드한 다음 컨테이너를 돌리게 됩니다.</p>
<pre><code>docker run node</code></pre><hr>

<p>docker run node 입력해 보시면 아무 일도 없이 끝나요. 뭐가 어떻게 됐는지 알고 싶죠?</p>
<pre><code>docker ps -a</code></pre><p>-a, all 옵션을 준 ps 커맨드로 node 컨테이너가 어떻게 되어 있는지 볼 수 있어요.</p>
<hr>

<pre><code>docker run -it node</code></pre><p>run 뒤에 it 옵션을 더하면 호스트에 interactive 세션이 만들어집니다.</p>
<p>이렇게 되면 컨테이너와 그 바깥에서 커뮤니케이션을 할 수가 있죠.</p>
<p>위 커맨드를 돌려 보시면 node 셸로 들어간다는 걸 알 수가 있습니다.</p>
<hr>

<p>이제 우리만의 이미지를 만들어 봅시다.</p>
<p>Dockerfile을 만들어 주세요.</p>
<p>FROM</p>
<ul>
<li>다른 이미지를 가져옵니다.</li>
<li>이를 베이스로 하여 customizing 할 수 있을 겁니다.</li>
</ul>
<p>WORKDIR</p>
<ul>
<li>Dockerfile 커맨드들을 어디에서 돌릴지 정해 줍니다.</li>
<li>컨테이너의 루트 path 말고 다른 path를 정해 주시는 게 좋습니다.</li>
</ul>
<p>COPY</p>
<ul>
<li>이미지에 첫 번째 인자로 주어진 파일들을 복사합니다.</li>
<li>첫 번째 인자: 호스트 OS에서 컨테이너에 필요한 디렉터리 또는 파일들을 정합니다.</li>
<li>두 번째 인자: 게스트 OS의 어디에 둘 것인지를 정합니다.</li>
<li>Dockerfile의 path를 베이스로 하는 상대경로를 써 주시면 됩니다.</li>
<li>두 번째 인자에서는 /에는 파일을 두지 마시고 디렉터리를 하나 만들어서 쓰시는 게 좋아요. WORKDIR처럼요.</li>
</ul>
<p>RUN</p>
<ul>
<li>이미지를 빌드할 때 이 커맨드를 돌립니다.</li>
</ul>
<p>EXPOSE</p>
<ul>
<li>컨테이너의 어떤 포트를 열어 둘 것인지 정합니다.</li>
<li>진짜로 포트를 여는 것은 아니며..! 그냥 docs 같은 느낌으로 쓰입니다.</li>
<li>진짜로 컨테이너 포트를 열어 두고 싶다면 컨테이너를 만들 때 -p 옵션을 줘야 합니다.</li>
</ul>
<p>CMD</p>
<ul>
<li>컨테이너가 주어진 커맨드를 돌립니다.</li>
<li>예를 들어 노드 서버를 띄우고 싶은데 이러한 것들은 이미지가 아닌 컨테이너에서 해야 합니다.</li>
<li>인자를 리스트 타입으로 입력하셔야 합니다.</li>
</ul>
<hr>

<h1 id="이미지의-아키텍처">이미지의 아키텍처</h1>
<p><span style="color: red">이미지는 레이어 베이스</span>입니다.</p>
<p>이게 무슨 말이냐면 이미지를 빌드하거나 다시 빌드할 때</p>
<p>Dockerfile에 있는 코드 라인을 하나씩 보면서</p>
<p><strong>새로운 코드 라인 또는 처음으로 바뀐 라인을 찾았으면 거기서부터</strong></p>
<p><strong>그 밑의 모든 라인들을 Docker가 (다시) 보게 됩니다</strong>.</p>
<p>코드 라인 하나하나를 레이어라 부르며, 그래서 이미지를 레이어 베이스 아키텍처로 되어 있다 합니다.</p>
<p>또한 <strong>한 번 빌드된 레이어들은 모두 캐시에 담깁니다</strong>.</p>
<p>Dockerfile을 바꾸지 않고 이미지를 다시 빌드하면</p>
<p>빌드가 정말 빠르게 이루어지는 것을 볼 수 있는데,</p>
<p>이것이 레이어들이 캐시에 담겨 있기 때문입니다.</p>
<p>어떤 이미지로 컨테이너를 돌리게 되면 컨테이너 레이어가 이미지 레이어 맨 위에 올라갑니다.</p>
<p>스택을 생각하시면 됩니다.</p>
<p>Dockerfile의 첫 번째 라인이 첫 번째 이미지 레이어가 되어 스택에 쌓이는 모습이요.</p>
<hr>

<h1 id="attached-detached-컨테이너">Attached, Detached 컨테이너</h1>
<p>이미지가 바뀌지 않았다면 새 컨테이너를 만들지 않아도 됩니다.</p>
<p>Exited status인 컨테이너를 재시작할 수 있거든요.</p>
<pre><code>docker start 컨테이너_ID 또는 이름</code></pre><p>다만 run 커맨드와 start 커맨드의 결과가 같은 것은 아닙니다.</p>
<p>run 커맨드는 컨테이너를 foreground에서, start 커맨드는 컨테이너를 background에서 돌립니다.</p>
<p>Foreground에서 돌아가는 컨테이너를 attached 컨테이너,</p>
<p>background에서 돌아가는 컨테이너를 detached 컨테이너라 합니다.</p>
<p>하지만 이것은 그냥 커맨드마다 디폴트 세팅이 그렇게 되어 있는 것뿐이고요,</p>
<p>여러분이 바라는 세팅으로 돌릴 수 있습니다.</p>
<p>run 커맨드에 -d 옵션을 붙이거나 start 커맨드에 -a 옵션을 붙이면 됩니다.</p>
<p>docker attach 커맨드도 있는데 이것은 돌아가고 있는 detached 컨테이너랑 터미널을 이어 줍니다.</p>
<p>아니면 그냥 로그만 가져오면 된다! 할 때 docker logs 커맨드가 있습니다.</p>
<p>이거는 리얼타임으로 가져오는 건 아니고 컨테이너에서 프린트된 로그들을 모두 보여 줍니다.</p>
<p>아니면 docker logs에 -f, follow 옵션을 줘서 tracking할 수도 있고요.</p>
<hr>

<h1 id="interactive-컨테이너">Interactive 컨테이너</h1>
<p>컨테이너에서 돌릴 애플리케이션에서 유저와 인터랙션을 할 수 있습니다.</p>
<p>docker run 커맨드에 -i, interactive 옵션을 주면 됩니다.</p>
<p>이 옵션을 주면 컨테이너와 인터랙션을 할 수 있습니다.</p>
<p>Attached 컨테이너든, detached 컨테이너든 상관없습니다.</p>
<p>여기에 -t, tty 옵션을 같이 주는 게 좋은데요, 인터랙션할 터미널을 만든다고 생각하시면 됩니다.</p>
<p>docker start 커맨드라면 -a, -i 옵션을 줘야 합니다. -ai로 줄일 수 있습니다.</p>
<hr>

<h1 id="이미지와-컨테이너-지우기">이미지와 컨테이너 지우기</h1>
<p>안 쓰는 컨테이너를 docker rm 커맨드로 지울 수 있습니다.</p>
<pre><code>docker rm $1, $2, $n, ...</code></pre><p>아니면 docker run 커맨드로 컨테이너를 돌릴 때 --rm 옵션을 넣어 주시면</p>
<p>컨테이너가 할 일을 끝냈을 때 알아서 없어집니다.</p>
<p>아, 이미지 리스트를 뽑고 싶을 때는 docker images 커맨드를 씁니다.</p>
<p>그리고 이미지를 지울 땐 docker rmi 커맨드를 씁니다.</p>
<p>다만 이미지를 지울 때는 이 이미지를 쓰고 있는 컨테이너가 없어야 합니다.</p>
<p>쓰지 않고 있는 이미지를 한 번에 지울 수 있는 docker image prune 커맨드도 있답니다.</p>
<hr>

<p>이미지에는 코드와 애플리케이션 환경이 들어가 있죠.</p>
<p>만들어진 컨테이너의 사이즈는 그렇게 크지 않습니다.</p>
<p>이미지 위에 올라간 하나의 레이어일 뿐이거든요.</p>
<hr>

<h1 id="docker-image-inspect">docker image inspect</h1>
<p>docker image inspect 커맨드로 이미지를 디테일하게 살펴볼 수 있습니다.</p>
<p>중요하게 볼만한 것으로는..</p>
<ul>
<li>이미지의 full ID</li>
<li>만들어진 날짜</li>
<li>만들어질 컨테이너 구성(ExposedPorts, Env, Cmd에 있는 ENTRYPOINT 등)</li>
<li>DockerVersion</li>
<li>OS</li>
<li>RootFS에 있는 레이어</li>
</ul>
<p>정도가 있습니다.</p>
<p>RootFS에 있는 레이어에는 Dockerfile에서 만들어진 레이어 말고도 여러 다른 레이어들이 있습니다.</p>
<p>예를 들면 FROM으로 가져오는 이미지 레이어들도 있어요.</p>
<hr>

<h1 id="컨테이너로-또는-밖으로-파일-또는-폴더-복사">컨테이너로, 또는 밖으로 파일 또는 폴더 복사</h1>
<p>돌아가고 있는 컨테이너에 어떤 파일을 주거나, 컨테이너로부터 어떤 파일을 받을 수 있습니다.</p>
<p>docker cp 커맨드를 쓰세요, 파일 또는 폴더를 컨테이너 안이나 바깥으로 복사할 수 있습니다.</p>
<hr>

<h1 id="컨테이너-이미지-이름-정하기">컨테이너, 이미지 이름 정하기</h1>
<pre><code>docker run --name 이름 컨테이너_ID</code></pre><p>컨테이너는 위 커맨드와 같이 이름만 주면 끝입니다.</p>
<p>이미지에는 이름뿐만 아니라 태그가 있습니다, name:tag 꼴입니다.</p>
<p>예를 들면 node:14 또는 node:12처럼요.</p>
<p><img src="https://velog.velcdn.com/images/jhanggun_kim/post/44ccc8fb-ac0c-4ef1-af43-1b26e33dafed/image.png" alt=""></p>
<p>이렇게 보시니 태그가 어떤 느낌인지 아시겠죠?</p>
<p>이미지의 이름은 이미지 그룹 같은 느낌이에요. node처럼요.</p>
<p>태그는 이미지 그룹 안에서 이 이미지의 버전 같이 쓰일 수 있습니다.</p>
<pre><code>docker build -t or --tag name:tag</code></pre><hr>

<h1 id="이미지-공유">이미지 공유</h1>
<p>이미지 공유를 위한 두 가지 방법을 알려 드릴게요.</p>
<ol>
<li>Dockerfile을 공유하세요.<ul>
<li>Dockerfile과 디렉터리, 코드 파일들을 함께 공유해야 할 겁니다.</li>
<li>이미지를 빌드해야 하죠.</li>
</ul>
</li>
<li>이미지를 공유하세요.<ul>
<li>이미지를 받으면 바로 컨테이너를 돌릴 수 있습니다.</li>
<li>빌드를 하지 않아도 됩니다.</li>
</ul>
</li>
</ol>
<p>이미지를 공유하기 위해 Docker Hub 또는 private registry를 쓰세요.</p>
<p>Docker Hub는 official Docker image registry입니다.</p>
<p>이미지 process, save, deploy 등에 쓰일 수 있는 여러 서비스들을 가지고 있습니다.</p>
<p>하지만 웬만하면 private registry를 많이 쓰게 될 거예요.</p>
<pre><code>docker push IMAGE_NAME

docker pull IMAGE_NAME</code></pre><p>Docker Hub에서 리포지터리 만들어 보시면 알겠지만 그냥 이미지입니다.</p>
<p>로컬에게 이미지가 Docker에서 만들어졌음을 알게 하려면,</p>
<p>이미지 이름을 여러분의 Docker 아이디/이미지 이름으로 바꿔 주시면 됩니다.</p>
<p>이를 위해 docker tag 커맨드를 써서 이름을 바꿔 봅시다.</p>
<p>커맨드 이름이 tag이긴 하지만 이름도 바꿀 수 있습니다, 심지어 태그를 안 줘도 돼요.</p>
<p>그리고 docker tag는 이름을 바꾼다기보다는 새 이름을 가진 똑같은 이미지를 복제하는 것입니다.</p>
<p>그리고 퍼블릭 리포지터리라고 하더라도 push 하는 것은 리밋이 걸려 있습니다.</p>
<p>이를 위해 docker login 커맨드로 로그인을 해야 합니다.</p>
<p>Push 하려고 하는 이미지의 Docker 아이디와 로그인한 이미지가 같아야 하죠.</p>
<p>데이터를 가져올 때는 로그인하지 않아도 되고요.</p>
<p>Priviate registry를 쓸 때는 push, pull 키워드와 IMAGE_NAME 사이에 registry에 대한 어드레스가 있어야 합니다.</p>
<p>그냥 쓰면 Docker Hub에 push, pull 하는 거예요.</p>
<p>docker run 커맨드로 정해 준 이미지가 로컬에 없으면 registry에서 이미지를 찾습니다.</p>
<p>로컬에 이미지가 있다면 바로 돌리고 (업데이트 체크 안 함),</p>
<p>그렇지 않다면 registry에서 이미지를 찾는데 recently 버전을 씁니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[첫 컨테이너]]></title>
            <link>https://velog.io/@jhanggun_kim/%EC%B2%AB-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</link>
            <guid>https://velog.io/@jhanggun_kim/%EC%B2%AB-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</guid>
            <pubDate>Sat, 03 Dec 2022 05:45:05 GMT</pubDate>
            <description><![CDATA[<p>컨테이너는 이미지 베이스이기 때문에, 첫 컨테이너를 위해 먼저 이미지를 만들도록 하겠습니다.</p>
<p>Dockerfile을 만들어야 합니다. 아래는 하나의 example입니다.</p>
<pre><code>FROM node:14

WORKDIR /app

COPY package.json .

RUN npm install

COPY . .

EXPOSE 3000

CMD [ &quot;node&quot;, &quot;app.mjs&quot; ]</code></pre><p>그리고 아래 Dockerfile 이미지를 빌드하는 커맨드를 돌려 봅시다.</p>
<pre><code>docker build .</code></pre><p><span style="color: gray">※ 빌드할 때 에러가 뜨면 Docker가 떠서 돌아가고 있는지 체크해 보세요.</span></p>
<p>이미지가 하나 만들어졌을 겁니다.</p>
<p>그리고 이미지의 아이디도 있을 거예요.</p>
<pre><code>docker run IMG_ID</code></pre><p>이렇게 만들어진 이미지를 돌릴 수 있습니다. (제대로 말하자면 이미지가 아니라 컨테이너를 돌리는 거긴 하지만, 지금은 넘어갑시다.)</p>
<p>그런데 이 이미지는 열어 둔 포트가 있으니 그 포트에 갈 수 있도록 세팅을 해 주어야 합니다.</p>
<pre><code>docker run -p 3000:3000 IMG_ID</code></pre><p>-p 옵션(publish)은 호스트 OS에서 컨테이너 포트로 이어질 수 있도록 해 줍니다.
<span style="color: gray">※ 호스트 OS: VM이 있을 때 VM이 만들어진 physical OS를 가리킴. 이때 VM의 OS를 게스트 OS라 함.</span></p>
<pre><code>docker run -p 80:8000 IMG_ID</code></pre><p>위와 같이 되어 있다면 호스트 OS의 80 포트에서 컨테이너의 8000 포트에 갈 수 있는 것이죠.</p>
<p><span style="color: red">컨테이너와 호스트 OS 사이에는 디폴트 커넥션이 없다</span>는 것을 잊지 마세요.</p>
<pre><code>docker ps</code></pre><p>이 커맨드는 돌아가고 있는 컨테이너 리스트를 보여 줍니다.</p>
<p>랜덤으로 주어진 이름이 보일 거예요.</p>
<pre><code>docker stop CONTAINER_NAME</code></pre><p>위 커맨드로 돌아가고 있는 컨테이너를 멈출 수 있어요.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[세팅]]></title>
            <link>https://velog.io/@jhanggun_kim/Docker-%EC%84%B8%ED%8C%85</link>
            <guid>https://velog.io/@jhanggun_kim/Docker-%EC%84%B8%ED%8C%85</guid>
            <pubDate>Sat, 03 Dec 2022 05:02:09 GMT</pubDate>
            <description><![CDATA[<p>컨테이너를 만들고 매니지먼트하려면 Docker가 있어야 합니다.</p>
<p><a href="https://docs.docker.com/get-docker/">여기</a>에서 다운로드 받을 수 있습니다.</p>
<hr>

<h1 id="macos-or-windows">MacOS or Windows</h1>
<p>위 링크에 보면 requirement들이 있는데,</p>
<p>읽어 보시고 컨디션을 맞출 수 있다면 Docker Desktop을,</p>
<p>그렇지 않다면 Docker Toolbox를 다운로드 받으세요.</p>
<hr>

<h1 id="리눅스">리눅스</h1>
<p>위와 같은 툴 없이 그냥 Docker를 쓸 수 있습니다.</p>
<hr>

<p>저는 <strong>Windows 10 Home</strong>을 쓰고 있기 때문에 Hyper-V 백엔드는 쓸 수 없더라고요.</p>
<p>WSL 2 백엔드를 쓰기 위해 <a href="https://learn.microsoft.com/en-us/windows/wsl/install">여기</a>를 봤습니다.</p>
<p><img src="https://velog.velcdn.com/images/jhanggun_kim/post/98071a5f-45b9-4cba-863f-5e9c55b4e57f/image.png" alt=""></p>
<p>윈도즈 안에 리눅스를 까는 거예요.</p>
<p>Docker 데스크톱에서 이 리눅스를 씁니다.</p>
<p>Docker 데스크톱을 다 깔았으면 CMD를 열어서 docker 커맨드를 입력해 보시고, 문제가 없으면 세팅을 마쳐도 좋습니다.</p>
<hr>

<h1 id="vscode">VSCode</h1>
<p>VSCode를 쓰신다면 Docker 익스텐션도 깔아 두시면 좋아요.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Docker란?]]></title>
            <link>https://velog.io/@jhanggun_kim/Docker%EB%9E%80</link>
            <guid>https://velog.io/@jhanggun_kim/Docker%EB%9E%80</guid>
            <pubDate>Fri, 02 Dec 2022 13:31:23 GMT</pubDate>
            <description><![CDATA[<p>Docker</p>
<ul>
<li>컨테이너를 만들고 매니지먼트할 수 있게 해 주는 툴.</li>
</ul>
<p>컨테이너</p>
<ul>
<li>A standardized unit of S/W.</li>
<li>다른 말로 코드 패키지라 할 수 있음, 이 패키지에는 코드 뿐만 아니라 코드가 돌아갈 수 있도록 해 주는 여러 dependency들도 들어가 있음. (OS 레벨까지는 아님, OS 레벨에서는 Docker 깔 거임.)</li>
<li>예를 들어 NodeJS 애플리케이션 컨테이너라면 NodeJS 코드랑 NodeJS 런타임 뿐만 아니라 이 코드가 돌아갈 수 있도록 해 주는 모든 툴이 같이 있는 것이 컨테이너.</li>
</ul>
<p>컨테이너를 떠올려 봅시다. 컨테이너에는 글로벌 스탠더드가 있습니다.</p>
<p>그렇기 때문에 배에 실을 때 생각을 덜 할 수 있죠.</p>
<p>Docker에서의 컨테이너도 그런 콘셉트를 따왔다는 것을 알고 있으면 좋습니다.</p>
<p>Docker가 깔려 있는 곳 어디서든 컨테이너를 문제 없이 가져올 수 있고</p>
<p>똑같은 컨디션에서 똑같은 애플리케이션의 아웃풋을 얻을 수 있는 것입니다.</p>
<p>예를 들면 OS마다 Python 버전이 달라서 애플리케이션이 똑같은 아웃풋을 낸다는 개런티가 없을 때 쓰면 좋겠죠?</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[EC2]]></title>
            <link>https://velog.io/@jhanggun_kim/EC2</link>
            <guid>https://velog.io/@jhanggun_kim/EC2</guid>
            <pubDate>Mon, 07 Nov 2022 09:21:04 GMT</pubDate>
            <description><![CDATA[<p>EC2는 IaaS입니다.</p>
<p>EC2는 아래와 같이 여러 가지 서비스를 제공합니다.</p>
<ol>
<li>EC2: VM입니다. EC2 인스턴스라고 부릅니다.</li>
<li>EBS: 데이터를 virtual 드라이브 또는 EBS 볼륨에 저장할 수 있습니다.</li>
<li>ELB: Load balancer.</li>
<li>ASG: Automated scailing.</li>
</ol>
<p>EC2의 인스턴스를 만들 때 여러 옵션이 있는데, 이들 가운데 bootstrap 스크립트(<strong>EC2 유저 데이터</strong>)에 대해 알고 있어야 합니다.</p>
<p>이것을 써서 머신이 처음 시작될 때 어떤 커맨드를 돌릴 것인지 정해 둘 수 있습니다.</p>
<p>예를 들면 소프트웨어를 깔고, 업데이트하는 등이 있겠죠.</p>
<hr>

<p>EC2 인스턴스를 만들 때 키 페어가 필요한데,</p>
<p>이 키 페어는 SSH를 통해 인스턴스에 로그인할 때 필요합니다.
(키 페어 타입은 RSA로 하세요.)</p>
<p>이 키 페어 데이터를 담고 있는 파일이 *.pem 파일입니다.</p>
<hr>

<h1 id="ec2-인스턴스-타입">EC2 인스턴스 타입</h1>
<p>EC2 인스턴스에는 naming convention이 있으니, 이를 읽을 줄 알면 좋습니다.</p>
<p>예) m5.2xlarge
    - m: 인스턴스 클래스
    - 5: 제너레이션 (하드웨어 퍼포먼스가 발전할 때마다 올라감)
    - 2xlarge: 인스턴스 클래스 크기, 클수록 더 많은 메모리와 CPU를 가짐</p>
<p><strong>인스턴스 클래스</strong>마다 어떻게 쓰이는지가 <span style="color: red">테스트</span>에 나올 수 있습니다.
    - 범용 인스턴스: 웹 서버, 코드 스토리지 등. Compute, 메모리, 네트워크 퍼포먼스 밸런스.
    - Compute Optimized: 컴퓨터 집약적 작업에 최적화(CPU 위주). 배치 프로세스, 미디어 transcoding, 고성능 웹 서버, HPC, 기계학습, 게임 서버 등.
    - 메모리 Optimized: 인메모리 DB, 분산 웹 스케일 캐시 저장소(ElasticCache), 대규모 비정형 데이터를 실시간으로 처리하는 애플리케이션 등.
    - 스토리지 Optimized: OLTP 시스템, DB, 인메모리 DB, 데이터 웨어하우스, 분산 파일 시스템 등.</p>
<hr>

<h1 id="시큐리티-그룹">시큐리티 그룹</h1>
<p><strong>보안 그룹은 EC2 인스턴스의 트래픽을 컨트롤</strong>합니다. 파이어월이죠.</p>
<p>Inbound 룰과 outbound 룰을 정하면 됩니다.</p>
<p>Inbound 룰은 바깥에서 EC2 인스턴스로 들어오는 트래픽에 대한 룰입니다.</p>
<p>디폴트로 모든 트래픽을 막으니, 허용 룰만 만들면 됩니다.</p>
<p>Outbound 룰은 EC2 인스턴스에서 바깥으로 나갈 때의 트래픽에 대한 룰입니다.</p>
<p>예를 들면, EC2에서 어떠한 웹 사이트에도 액세스할 수 있습니다.</p>
<p>디폴트로 모든 트래픽을 열어 두니, 필요한 경우 룰을 만들면 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/jhanggun_kim/post/edb0e43d-5fbb-49d7-b82c-9799f13a0655/image.png" alt=""></p>
<p>Inbound 룰을 정하는 페이지입니다.</p>
<ul>
<li>유형: 어떤 프로토콜의 트래픽에 대한 룰인지 정합니다. SSH, HTTP 등이 있고 사용자 지정 프로토콜으로 정할 수도 있습니다.</li>
<li>프로토콜: 위 유형에 따라 정해집니다. 사용자 지정 프로토콜인 경우 직접 쓰면 됩니다.</li>
<li>포트 범위: 위 유형에 따라 정해집니다. 사용자 지정 프로토콜인 경우 직접 쓰면 됩니다.</li>
<li>소스: 위 이미지처럼 사용자 지정인 경우는 옆에 있는 칸에서 IP 주소 또는 IP 주소 범위를 쓰면 되고, 사용자 지정 말고는 모든 IPv4, 모든 IPv6, My IP 옵션이 있습니다.</li>
</ul>
<hr>

<p>보안 그룹에서 정해 놓은 룰들은 region에 종속됩니다.</p>
<p>그리고 보안 그룹은 EC2 안에 있는 애플리케이션이 아니라 바깥에 있는 파이어월입니다.</p>
<p>따라서 트래픽이 막히면 EC2 인스턴스에 액세스할 수 없습니다.</p>
<hr>

<p>디폴트 포트는 알고 있는 게 좋겠죠.</p>
<ul>
<li>22: SSH, 리눅스에서 EC2 인스턴스에 로그인할 수 있게 해 주는 역할입니다.</li>
<li>21: FTP</li>
<li>22: SFTP, 잘못 쓴 거 아닙니다. SSH를 쓰는 FTP입니다.</li>
<li>80: HTTP, 보안이 되어 있지 않은 웹 사이트에 액세스할 수 있습니다.</li>
<li>443: HTTPS</li>
<li>3389: RDP(Remote Desktop Protocol), 윈도즈 인스턴스에 로그인할 수 있게 해 줍니다.</li>
</ul>
<hr>

<p>SSH는 CLI를 쓰는 어떠한 터미널(remote 머신)을 컨트롤합니다.</p>
<p>SSH는 CLI 툴로, Mac, 리눅스, 윈도즈 10 이상 버전에서 쓸 수 있습니다.</p>
<p>10 미만 버전이면 PuTTY 쓰시면 되고요. PuTTY = SSH입니다.</p>
<p>어 그리고 다른 방법으로 EC2 인스턴스 커넥트라는 것도 있습니다.</p>
<p>이거는 웹 브라우저로 EC2 인스턴스에 연결하는 도구입니다.</p>
<p>OS 상관없이 다 쓸 수 있지만, 지금은 Amazon Linux2에서만 쓸 수 있습니다.</p>
<hr>

<p>그리고 EC2 인스턴스에 IAM 롤을 정할 수 있다는 점을 잊지 마시고요.</p>
<p>예를 들어 어떤 IAM 롤에 IAMReadOnlyAccess 권한을 준 뒤,</p>
<p>EC2 인스턴스에 위 IAM 롤을 줬다면 EC2 인스턴스에서 aws iam list-users 쳤을 때 관련 정보가 나올 겁니다.</p>
<hr>

<h1 id="ec2-인스턴스-옵션">EC2 인스턴스 옵션</h1>
<p>EC2 인스턴스에는 여러 가격 옵션들이 있습니다.</p>
<p>EC2 인스턴스에게 어떤 일을 시킬 것인지에 따라서 어떤 옵션을 고를지 알아야 싸게 쓸 수 있습니다.</p>
<p><span style="color: red">테스트</span>에서도 <strong>중요한</strong> 파트입니다!</p>
<ul>
<li>온 디맨드 인스턴스<ul>
<li>짧은 일에 알맞습니다.<ul>
<li>OS가 리눅스 또는 윈도즈인 경우 인스턴스가 돌고 나서 첫 1분이 지난 뒤부터, 인스턴스를 쓰는 초 만큼 내면 되기 때문에 가격을 예측할 수 있습니다.</li>
<li>다른 OS들은 인스턴스가 돌고 있는 매 시간 단위로 가격이 올라갑니다.</li>
<li>조금 비싼 편이지만 선결제를 하지 않아도 되고, 장기 약정도 없습니다.</li>
<li>쓰고 싶을 때 쓰고, 멈추고 싶을 때 멈추고, 없애고 싶으면 없애면 됩니다.</li>
<li>애플리케이션이 어떻게 될지 알 수 없는, 연속적인 단기 태스크 위주일 때 좋습니다.</li>
</ul>
</li>
</ul>
</li>
<li>예약 인스턴스<ul>
<li>최소 1년 이상 써야 합니다. 구체적으로 1년 또는 3년 중에 하나를 고르면 됩니다.<ul>
<li>온 디맨드에 비해 약 75%의 비용을 절약할 수 있습니다. 당연히 3년이 더 싸겠죠.</li>
<li>또 선결제를 해도 되고, 부분적으로만 할 수도 있고, 안 할 수도 있습니다. 선결제가 가장 쌉니다.</li>
<li>예약 인스턴스는 3가지로 나뉩니다.</li>
</ul>
</li>
<li>예약 인스턴스: DB처럼 일을 계속 해야 할 때 알맞습니다.</li>
<li>전환형 예약 인스턴스: 첫 예약 기간이 끝난 뒤 다른 인스턴스로 바꿀 수 있습니다. 대신 할인율은 54%로 조금 낮습니다.<ul>
<li>정기 예약 인스턴스(지금은 없는 서비스지만 시험에는 나올 수 있음): 기간 내내는 아니지만 긴 기간 동안 특정일, 또는 특정시간에 돌아가는 일에 알맞습니다. 딱 스케줄러가 떠오르네요.</li>
</ul>
</li>
</ul>
</li>
<li>스폿 인스턴스<ul>
<li>온 디맨드와 비교했을 때 최대 90%까지 싸게 쓸 수 있는 인스턴스입니다.<ul>
<li>스폿 인스턴스의 가격은 계속 바뀝니다. 만약 여러분이 낸 가격이 스폿 인스턴스의 현재 가격보다 낮다면 인스턴스가 언제든지 중단될 수 있으므로, 꼭 체크가 필요합니다.</li>
</ul>
</li>
<li>싼 대신에 손실 가능성이 있고 신뢰도가 낮습니다.<ul>
<li>따라서 갑자기 멈춰져도 다시 하기 쉬운 일이 알맞겠죠. 예를 들어 단발성 데이터 분석인 배치, 이미지 processing, 분산된 일들(여러 서버에 일을 나누어 놓아 하나가 안 되면 다른 서버에서 뭔가 할 수 있는), 일의 시작과 끝 시간이 유연한 일들.</li>
<li>반대로 중요한 일이나, 특히 DB는 절대 이 인스턴스를 쓰면 안 되겠죠.</li>
</ul>
</li>
</ul>
</li>
<li>전용 호스트<ul>
<li>물리적 서버 전체를 예약하고, 인스턴스 배치를 컨트롤할 수 있습니다.<ul>
<li>즉 AWS 데이터 센터에 있는 하나의 서버를 통으로 빌리는 거죠.</li>
<li>전용 호스트를 쓰면 <strong>준수 요건</strong>(compliance requirements)에 맞추기가 쉽고, 기존의 <strong>서버 결합(server-bound) 소프트웨어 라이선스</strong>를 쓸 수 있기 때문에 코스트를 줄일 수 있습니다. 어쨌든 서버를 통으로 빌리는 거니까 애초에 비싸긴 하겠죠.</li>
<li>3년간 써야 합니다.</li>
<li>복잡한 라이선스 모델의 S/W를 쓰거나 자가 라이선스를 가진 케이스, 혹은 강력한 규제나 규정 준수 요건이 있는 케이스, 여러분만 쓸 수 있는 물리적 서버가 필요할 수 있는데 그럴 때 많은 도움이 될 것입니다.</li>
</ul>
</li>
</ul>
</li>
<li>전용 인스턴스<ul>
<li>여러분의 전용 H/W에서 돌아가는 EC2 인스턴스를 말합니다.<ul>
<li>같은 계정의 다른 인스턴스와 H/W를 공유합니다.</li>
<li>인스턴스가 어떻게 배치될지는 여러분이 컨트롤할 수 없습니다.</li>
<li>전용 호스트와 마찬가지로 지켜야 할 것이 있어 H/W를 다른 사람과 공유하고 싶지 않을 때 알맞습니다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>

<h1 id="스폿-인스턴스">스폿 인스턴스</h1>
<p>만약 현재의 스폿 인스턴스 가격이 여러분이 정한 가격을 넘어버리면 2분의 시간이 주어집니다.</p>
<p>그 안에 인스턴스를 중단시킬 것인지, 종료시킬 것인지 정해야 하죠.</p>
<p>중단한다면,</p>
<p>나중에 스폿 인스턴스의 가격이 여러분이 정한 가격 아래로 내려갈 때 중단했던 그 부분부터 다시 쓸 수 있습니다.</p>
<p>종료시킨다면 인스턴스를 없애는 것이고, 위와 같은 상황이 되었을 때 처음부터 다시 쓸 수 있습니다.</p>
<p>또 다른 전략은 <strong>스폿 블록</strong>인데요. 곧 없어질 서비스지만 아직 <span style="color: red">테스트</span>에는 나오고 있으니 한 번 알아봅시다.</p>
<p>이 전략을 쓰면 AWS로부터 인스턴스를 빼앗길 일이 없어집니다.</p>
<p>스폿 인스턴스를 1 to 6시간 안으로 &quot;블록&quot;하여,</p>
<p>AWS가 인스턴스를 &quot;회수&quot;하는 일이 일어나지 않도록 하는 것입니다.</p>
<hr>

<h1 id="스폿-플리트">스폿 플리트</h1>
<p><strong>스폿 플리트</strong>는 강력한 코스트 절감 방법으로,</p>
<p><strong>한 세트의 스폿 인스턴스에 선택적으로 온 디맨스 인스턴스를 섞어 쓰는 것</strong>을 말합니다.</p>
<p>여러분은 스폿 플리트에게 코스트와 capacity를 말해 주시면 됩니다.</p>
<p>그러면 스폿 플리트는 정해진 코스트 안으로 타깃 capacity를 만족시키려 할 것입니다.</p>
<p>하나의 launch pool은 <strong>여러 인스턴스 타입</strong>, OS, AZ를 가지는데,</p>
<p>이러한 풀이 여러 개 있으니 여러분이 생각해야 한다면 꽤 많은 시간이 걸릴 수 있는 일입니다.</p>
<p>스폿 플리트 덕분에 그런 생각은 할 필요가 없죠.</p>
<p>그리고 스폿 인스턴스들을 스폿 플리트 안에 어떻게 할당시킬 건지에 대한 여러 <strong>전략</strong>이 있습니다.</p>
<ul>
<li>lowestPrice: 가장 싼 풀부터 인스턴스를 실행시킵니다. 싸게 쓸 수 있으며, 짧게 끝나는 일을 할 때 알맞습니다.</li>
<li>diversified: 스폿 인스턴스들을 여러분이 정해 놓은 모든 풀에 걸쳐 분산시킵니다. 가용성이 좋겠죠? 하나의 풀이 중단되더라도 다른 풀은 계속 돌아갈 테니까요. 길게 걸리는 일을 할 때 알맞습니다.</li>
<li>capacityOptimized: 인스턴스의 개수에 따라 최적화된 용량으로 실행될 것입니다.</li>
</ul>
<p>만약 정해진 코스트나 capacity를 벗어나게 되면 돌아가고 있는 인스턴스들을 중단 또는 종료시킵니다, 여러분이 정할 수 있습니다.</p>
<hr>

<h1 id="배치-그룹">배치 그룹</h1>
<p><strong>배치 그룹</strong>은 EC2 인스턴스가 AWS 인프라에 어떻게 배치될지 방식을 컨트롤하고 싶을 때 씁니다.</p>
<p>배치 그룹을 만들 때 3가지 전략 중 하나를 고르게 될 것입니다.</p>
<ol>
<li>클러스터<ul>
<li>하나의 랙(H/W), 하나의 AZ에 여러 인스턴스를 배치.</li>
<li>빠른 네트워크 스피드.</li>
<li>랙에 실패가 생기면 모든 EC2 인스턴스가 동시에 실패.</li>
<li>빠른 스피드가 필요한 빅 데이터 태스크나, 정말 짧은 지연시간과 높은 네트워크 처리량을 필요로 하는 애플리케이션에 알맞음.</li>
</ul>
</li>
<li>스프레드<ul>
<li>인스턴스들이 다른 랙에 분산 배치됨.</li>
<li>위험을 줄일 수 있음.</li>
<li>하나의 AZ당 최대 7개의 인스턴스만 배치할 수 있고, 하나의 AZ에 최대 7개의 랙을 가질 수 있음.</li>
<li>가용성이 높아야 하는 케이스, 위험을 줄여야 하는 크리티컬 애플리케이션에 알맞음.</li>
</ul>
</li>
<li>파티션<ul>
<li>인스턴스가 여러 파티션에 분산 배치됨.</li>
<li>AZ마다 최대 7개의 파티션만 배치할 수 있음.</li>
<li>파티션마다 배치할 수 있는 EC2 인스턴스의 수에는 리밋이 없음.</li>
<li>파티션은 같은 region에 있는 여러 AZ에 걸쳐 있을 수 있음.</li>
<li>위험이 파티션별로 고립됨.</li>
<li>스프레드보다는 위험이 조금 높음.</li>
<li>그룹당 수백 개의 EC2 인스턴스를 통해 확장할 수 있고 이를 통해 Hadoop, Cassandra, Kafka 같은 애플리케이션을 돌릴 수 있음.</li>
<li>파티션을 인식할 수 있는 빅 데이터 애플리케이션들을 쓰기에 알맞음.</li>
</ul>
</li>
</ol>
<hr>

<h1 id="ebs">EBS</h1>
<p>EBS(Elastic Block Store) 볼륨은 EC2 인스턴스가 돌아가고 있을 때 쓸 수 있는 <strong>네트워크 드라이브</strong>입니다.
(Physical 드라이브가 아닙니다!)</p>
<p>볼륨이기 때문에 원하는 capacity, IOPS를 미리 정해 주어야 합니다.</p>
<p>정한 만큼의 코스트가 생길 거고요, 나중에 바꿀 수도 있습니다.</p>
<p>인스턴스와의 커뮤니케이션을 위해 네트워크를 쓰기 때문에 지연이 있을 수 있습니다.</p>
<p>EC2 인스턴스를 끈(shut down) 뒤에도 데이터들은 <strong>남아 있습니다</strong>.</p>
<p>서로 독립적인 거니까요.</p>
<p>따라서 인스턴스를 다시 만들고 이전 EBS 볼륨을 마운트 하면 그 데이터들을 다시 쓸 수 있습니다.</p>
<p>다른 인스턴스에 빠르게 커넥션을 만들 수도 있고요.</p>
<p>그리고 EBS 볼륨들은 <strong>AZ에 종속</strong>되어 있습니다.</p>
<p>다른 AZ에 옮기고 싶으면 스냅숏을 쓰면 됩니다.</p>
<p>다음은 <span style="color: red">테스트</span>에 나올 수 있는데요, <strong>EC2 인스턴스를 없앨 때 EBS 볼륨을 같이 없앨 수 있습니다.</strong></p>
<p><strong>루트 볼륨은 디폴트 값으로 체크가 되어 있고요, 나머지 볼륨에 대해서는 그렇지 않습니다.</strong></p>
<p>여러분이 원하시는 대로 세팅을 바꾸시면 됩니다.</p>
<hr>

<h1 id="ami">AMI</h1>
<p>EC2 인스턴스의 베이스가 되는 AMI(Amazon Machine Image)에 대해 조금 알아보고 갑시다.</p>
<p>쉽게 말하자면 커스텀 EC2 인스턴스라 할 수 있습니다.
    - 여러 S/W들, 세팅들, OS, 모니터링 시스템 등을 정해 놓을 수 있습니다.
    - 미리 다 정해 놔서 부팅 및 세팅 타임이 많이 줄어들겠죠.
    - 어떤 region에 맞게 짤 수도 있고, 다른 region에 복사도 할 수 있고요.</p>
<p>이러한 AMI는 AWS에서 만들어 놓은 게 있고요, 여러분이 만들 수도 있고요, 마켓플레이스에서 구할 수도 있습니다.</p>
<p>AMI 프로세스는 다음과 같습니다.
    - EC2 인스턴스를 켠 뒤 customize.
    - 인스턴스를 끈 뒤 데이터 무결성 확보.
    - 빌드 AMI, EBS 스냅숏도 만들어짐.</p>
<hr>

<h1 id="ec2-인스턴스-스토어">EC2 인스턴스 스토어</h1>
<p>EBS 볼륨은 네트워크 드라이브라 퍼포먼스에 리밋이 있습니다.</p>
<p><strong>높은 퍼포먼스</strong>가 있어야 된다면 <strong>EC2 인스턴스 스토어</strong>를 쓰세요.</p>
<p>EC2 인스턴스는 VM이지만 하드웨어 서버랑 커넥션이 있습니다.</p>
<p>EC2 인스턴스 스토어를 쓸 때 잊으면 안 되는 점이 있는데,</p>
<p>스토어가 멈추게 되면 인스턴스 스토어의 콘텐츠들을 잃게 될 수 있습니다.</p>
<p>그래서 EC2 인스턴스 스토어를 temporarily 스토리지라 부릅니다.</p>
<p>따라서 버퍼, 캐시 같이 잠깐 쓰는 콘텐츠를 담는 것이 좋겠죠.</p>
<p>또한 EC2 인스턴스에 에러가 생기면 스토어에도 이펙트가 가서 콘텐츠를 잃을 수 있습니다.</p>
<p>그러니 백업이나 복제본을 만들어 둬야 할 수 있습니다.</p>
<hr>

<p>EC2 인스턴스는 AWS 네트워크에선 프라이빗 IP 어드레스를, WWW에선 퍼블릭 IP 어드레스를 씁니다.</p>
<p>EC2 인스턴스를 멈췄다가 다시 시작하면 퍼블릭 IP 어드레스가 바뀝니다.</p>
<p>만약 멈췄다가 다시 시작해야 하는데 어드레스가 바뀌는 게 싫다면 EIP를 쓰세요.</p>
<p>※ EIP는 만들어 놓고 쓰지 않으면 코스트가 생깁니다.</p>
<hr>

<h1 id="eni">ENI</h1>
<p>ENI(Elastic Network Interface)에 대해 알아봅시다.</p>
<p>VPC의 엘리먼트 가운데 하나로, virtual 네트워크 카드입니다.</p>
<p>ENI는 EC2 인스턴스가 네트워크에 액세스할 수 있게 해 줍니다.</p>
<p>EC2 인스턴스를 만들면 디폴트 ENI인 Eth0에 이어져</p>
<p>바로 EC2 인스턴스에게 네트워크를 쓸 수 있게 해 줍니다.</p>
<p>ENI들은 아래와 같은 캐릭터들을 갖습니다.</p>
<ul>
<li>프라이빗 IPv4를 갖고, 하나 이상의 보조 IPv4를 가질 수 있습니다.</li>
<li>프라이빗 IPv4마다 EIP 어드레스를 가질 수 있습니다.</li>
<li>하나의 퍼블릭 IPv4를 가질 수 있습니다.</li>
<li>하나 이상의 시큐리티 그룹에 들어갈 수 있습니다.</li>
</ul>
<p>ENI는 EC2 인스턴스에 종속되는 게 아니라, <strong>AZ에 종속</strong>됩니다.</p>
<p>그냥 ENI를 따로 만들 수도 있고요.</p>
<p>EC2 인스턴스 장애 조치를 위해 여러 ENI를 이을 수도 있습니다.</p>
<p>A 인스턴스에 Eth0, Eth1를 이어 놓고 B 인스턴스에 Eth0을 이었다 칩시다.</p>
<p>A 인스턴스에 에러가 생겼을 때 Eth1을 B로 옮겨서 프라이빗 IP 어드레스를 이동시킬 수 있는 겁니다.</p>
<p>이를 위해선 EC2 인스턴스의 네트워크 인터페이스 메뉴에서 액션 메뉴의 Detach 아이템을 쓰면 됩니다.</p>
<p>ENI에 코스트는 붙지 않습니다.</p>
<hr>

<h1 id="ec2-hibernate">EC2 Hibernate</h1>
<p>EC2의 새 기능인 절전 모드(hibernate)에 대해 알아봅시다.</p>
<p>EC2 인스턴스를 처음으로 시작할 땐 OS를 부팅시키고 유저 데이터에서 스크립트를 돌립니다.</p>
<p>그 다음에 애플리케이션을 돌리고, 캐시도 준비시킵니다.</p>
<p>가벼운 일은 아니죠?</p>
<p>그래서 절전 모드가 생겼습니다.</p>
<p>절전 모드를 하면 메모리가 보존됩니다. OS를 멈추지도 않고요.</p>
<p>그래서 절전 모드에서 인스턴스를 다시 시작하면 부팅이 굉장히 빨리 되겠죠.</p>
<p>어떻게 메모리가 보존되는 걸까요?</p>
<p>램의 스테이트를 <strong>루트 EBS 볼륨에</strong> 넣는 겁니다, 따라서 이 볼륨을 암호화해 놓을 필요가 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/jhanggun_kim/post/3e379b1f-f8f6-4683-be19-cf18231d4527/image.png" alt=""></p>
<p>흐름은 위와 같습니다.</p>
<p>메모리가 인스턴스에서 암호화된 EBS <strong>루트 볼륨</strong>으로,</p>
<p>나중에는 다시 인스턴스로 가는 걸 볼 수 있죠.</p>
<p>유즈 케이스로는 오래 돌아가는 프로세스, 초기화가 오래 걸리는 서비스인 케이스 등이 있습니다.</p>
<p>절전 모드는 나온지 그렇게 오래 되지 않아 아직 에러가 있을 수 있다 합니다.</p>
<p>모든 EC2 인스턴스가 절전 모드를 쓸 수 있는 것은 아닙니다.</p>
<p>인스턴스 타입에 따라 갈립니다.</p>
<p><strong>인스턴스의 램 사이즈는 150GB 아래여야</strong> 하고요.</p>
<p><strong>스폿 인스턴스에서는 못 씁니다</strong>.</p>
<p>그리고 60일 넘게 절전 모드로 둘 수 없습니다.</p>
<hr>

<h1 id="ec2-니트로">EC2 니트로</h1>
<p>니트로 시스템은 다음 제너레이션의 EC2 인스턴스를 위한 디폴트 플랫폼입니다.</p>
<p>낡은 virtualization 기술을 업그레이드했습니다.</p>
<p>퍼포먼스가 올라갔습니다, 디테일하게 보자면 아래와 같습니다.
    - 더 나아진 네트워킹 옵션들을 고를 수 있습니다. 예를 들어 HPC, IPv6 등이 있습니다.
    - <strong>더 빠른 EBS 볼륨</strong>을 오퍼합니다. 니트로 없이는 32000IOPS까지만 오퍼하는데 니트로를 쓰면 <strong>64000IOPS</strong>까지도 오퍼합니다.</p>
<p>두 번째는 vCPU입니다.</p>
<p>예를 들어 m5.2xlarge에는 physical 코어가 4개가 있고 코어당 디폴트 스레드는 2개 있으면 vCPU는 8개가 있다고 합니다.
(<a href="https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/cpu-options-supported-instances-values.html#cpu-options-gen-purpose">https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/cpu-options-supported-instances-values.html#cpu-options-gen-purpose</a>)</p>
<p>vCPU에 대해 알고 있는 것은 &#39;CPU 옵션의 optimization을 할 수 있다&#39;로 이어집니다.</p>
<p>예를 들어 하이 퍼포먼스 램이 필요한데 많은 코어는 필요하지 않을 때,</p>
<p>코어 수를 줄여 돈을 아낄 수 있거든요. AWS에게 물어 보면 해 주고요.</p>
<p>아니면 코어당 스레드 수를 줄일 수도 있습니다.</p>
<p>예를 들어 HPC로 쓸 때는 코어당 하나의 스레드만 갖는 게 유리하거든요.</p>
<p>이런 경우에도 AWS에게 해 달라고 말할 수 있습니다.</p>
<p>위 링크에서 볼 수 있듯이 고를 수 있는 옵션들을 쉼표로 나누어 놓은 것을 볼 수 있습니다.</p>
<p>이 옵션들은 인스턴스를 시작할 때만 바꿀 수 있습니다.</p>
<hr>

<h1 id="ec2-capacity-reservation">EC2 Capacity Reservation</h1>
<p>EC2 인스턴스를 시작할 때 바라는 capacity를 가질 수 있게 해 줍니다.</p>
<p>Reservation에 대해 날짜를 정하고, 언제까지 가지고 있을 건지도 정할 수 있습니다.</p>
<p>다만 이 reservation은 짧은 reservation입니다. 1년 또는 3년, 이런 게 아닙니다.</p>
<p>어떤 피리어드에 어떤 인스턴스 타입을, 어떤 AZ에서 인스턴스를 시작해야 하는지 알 때 도움이 될 것입니다.</p>
<hr>

<h1 id="ebs-볼륨-타입">EBS 볼륨 타입</h1>
<ol>
<li><strong>gp2 / gp3</strong><ul>
<li>General-purpose의 <strong>SSD</strong> 볼륨.</li>
<li><strong>Efficient 코스트</strong>, 짧은 지연.</li>
<li>1GB to 16TB.</li>
<li><strong>gp2는 볼륨과 IOPS가 이어져 있기 때문에 볼륨을 늘리면 IOPS도 늘어남</strong>.</li>
<li><strong>gp3는 가장 새로운 볼륨으로 볼륨과 IOPS가 이어져 있지 않음.</strong></li>
</ul>
</li>
<li><strong><span style="color: red">io1 / io2 (Provisioned IOPS SSD ; PIOPS SSD)</span></strong><ul>
<li>가장 좋은 퍼포먼스의 <strong>SSD</strong> 볼륨.</li>
<li>4GB to 16TB.</li>
<li>낮은 지연, 대용량의 일에 알맞음.</li>
<li>IOPS 퍼포먼스가 어느 정도 있어야 하는 중요한 비즈니스 애플리케이션에 알맞음.</li>
<li>16000IOPS 이상의 퍼포먼스를 바라는 애플리케이션(DB 등)에 알맞음.</li>
<li>맥시멈 32000IOPS까지 올릴 수 있으며, 니트로라면 64000IOPS까지 올릴 수 있음.</li>
<li><strong>gp3처럼 볼륨과 IOPS가 이어져 있지 않음</strong>.</li>
<li>io1 &lt; io2: 코스트가 똑같아도 더 튼튼하고 IOPS 높음.</li>
<li><strong>io2 블록 익스프레스</strong>: 4GB to 64TB. 밀리세컨드 단위의 지연을 뽐내는 하이 퍼포먼스 볼륨. <strong>256000IOPS까지</strong> 올릴 수 있음.</li>
</ul>
</li>
<li><strong>st1</strong><ul>
<li>싼 <strong>HDD</strong> 볼륨.</li>
<li><strong>액세스가 자주</strong> 일어나면서 <strong>높은 처리량</strong>이 필요한 일에 알맞음.</li>
<li>빅 데이터, 데이터 웨어하우스, 로그 등에 쓰임.</li>
</ul>
</li>
<li><strong>sc1</strong><ul>
<li>가장 싼 <strong>HDD</strong> 볼륨.</li>
<li><strong>콜드 볼륨</strong>이라고 부르기도 함.</li>
<li><strong>액세스가 가끔</strong> 일어나는 일에 알맞음.</li>
</ul>
</li>
</ol>
<p>EBS의 부팅 볼륨은 SDD 볼륨들만 될 수 있습니다.</p>
<p><strong>디폴트로 EBS는 하나의 EC2 인스턴스에만 이을 수 있습니다.</strong></p>
<p><strong>io1, io2는 빼고요. 얘네는 <span style="color: red">하나의 EBS 볼륨</span>에 여러 EC2 인스턴스를 이을 수 있습니다, 같은 AZ에 있으면요.</strong></p>
<hr>

<h1 id="ebs-encryption">EBS Encryption</h1>
<p>인스턴스와 볼륨 사이 주고 받는 모든 데이터가 암호화되고,</p>
<p>모든 스냅숏이 암호화되고,</p>
<p>스냅숏으로 만든 모든 볼륨도 암호화됩니다.</p>
<p>암호화가 지연시간에 미치는 이펙트는 거의 없습니다.</p>
<p>암호화를 위해 KMS 키를 씁니다.</p>
<p>아래는 <span style="color: red">EBS 볼륨을 암호화하는 방법</span>입니다.</p>
<ul>
<li>먼저 볼륨의 EBS 스냅숏을 만듭니다.</li>
<li>copy 함수로 EBS 스냅숏을 암호화합니다.</li>
<li>스냅숏으로 만들어진 볼륨들은 암호화됩니다.</li>
<li>이제 암호화된 볼륨을 오리지널 인스턴스와 이을 수 있습니다.</li>
</ul>
<hr>

<h1 id="efs-elastic-file-system">EFS (Elastic File System)</h1>
<p><strong>여러 AZ에 걸쳐</strong> 여러 EC2 인스턴스에 마운트 할 수 있는 managed NFS(네트워크 파일 시스템)입니다.</p>
<p>여러 AZ에 걸쳐 쓸 수 있다는 게 EBS와의 가장 큰 차이점입니다.</p>
<p>가용성과 확장성이 뛰어나고, 그만큼 비싸기도 합니다.
(쓰는 만큼 capacity가 늘거나 줄어듭니다, PB 단위까지 늘어납니다.)</p>
<p>쓴 만큼만 내면 되기는 하니까 잘 쓰기만 한다면 좋을 겁니다.</p>
<p>EFS는 시큐리티 그룹에 묶여 있고, 여러 EC2가 시큐리티 그룹을 통해 EFS와 커넥션을 만듭니다.</p>
<p>한 번에 하나의 EC2 인스턴스와만 커넥션을 만들 수 있습니다.</p>
<p>유즈 케이스: 콘텐츠 관리, 웹 서비스, 데이터 공유 등이 있습니다.</p>
<p><strong>EFS는 윈도즈가 아닌 리눅스 based AMI에서만 쓸 수 있습니다.</strong></p>
<p>최대 1000명의 동시 클라이언트를 다룰 수 있고 초당 10GB 이상의 처리량을 자랑합니다.</p>
<p>그리고 <strong>2가지 모드</strong>가 있습니다. EFS를 만들 때 퍼포먼스 모드와 처리량 모드를 정해 주어야 합니다.</p>
<p>모드마다 2가지 옵션이 있습니다.</p>
<p>먼저 퍼포먼스 모드에서는,</p>
<ol>
<li>범용 모드는 디폴트 모드로, 범용성이 좋습니다. 지연시간에 민감한 경우 알맞습니다. </li>
<li>Max I/O 모드는 지연시간은 좀 더 길지만 처리량이 높고 병렬성도 높습니다. 빅 데이터나 미디어 작업에 알맞습니다.</li>
</ol>
<p>두 번째 모드는 처리량 모드입니다.</p>
<ol>
<li>디폴트는 bursting 처리량 모드로, 1TB의 storage에 대해 초당 50MB를 저장할 수 있고 초당 100MB까지 확장이 가능합니다.</li>
<li>Provisioned 처리량 모드는 storage의 크기에 상관없이 처리량을 정하고 싶을 때 쓰면 됩니다. 예를 들어 1TB의 storage에 대해 초당 1GB의 처리량을 요청할 수 있습니다.</li>
</ol>
<hr>

<h1 id="스토리지-레벨">스토리지 레벨</h1>
<p>마지막으로 <span style="color: red">테스트</span>에 나올 수 있는 또 다른 토픽입니다.</p>
<p>파일에 대한 수명 주기 매니지먼트 기능으로, 디폴트 값이면 30일이 지나면 새로운 레벨로 파일을 옮깁니다.</p>
<ol>
<li>자주 액세스하는 파일은 스탠더드 계층에 남아 있습니다.</li>
<li>로 코스트의 액세스 빈도가 낮은 파일은 EFS-IA(Infrequent Access) 계층으로 옮겨집니다. 디폴트 값이면 30일 이후입니다. 여기에 있는 파일들은 가져올 때마다 코스트가 생깁니다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[CLI]]></title>
            <link>https://velog.io/@jhanggun_kim/AWS-CLI</link>
            <guid>https://velog.io/@jhanggun_kim/AWS-CLI</guid>
            <pubDate>Sat, 05 Nov 2022 07:08:57 GMT</pubDate>
            <description><![CDATA[<p>AWS에 액세스 하는 방법에는 아래와 같은 것들이 있습니다.</p>
<ol>
<li>AWS Management 콘솔. 패스워드 + MFA 쓰기.</li>
<li>AWS CLI(Command Line Interface). 터미널에서 액세스 키로 액세스.</li>
<li>AWS SDK(S/W Development Kit). 애플리케이션 코드에서 call AWS APIs. 액세스 키 쓰기.</li>
</ol>
<p><span style="color: red">액세스 키</span>는 IAM의 유저 메뉴에서 만들 수 있습니다.
패스워드랑 다를 바가 없으므로 <strong>공유하지 마세요</strong>!</p>
<p>SDK에 대해 좀 더 얘기하자면,
어떤 랭귀지로 되어 있는 라이브러리 세트라 할 수 있습니다.
참고하자면 Python의 AWS SDK는 Boto3입니다.</p>
<p>참고로 AWS CloudShell이라는 서비스가 있는데, 공짜로 쓸 수 있는 터미널이라고 생각하시면 됩니다.
쓸 수 있는 region 아직 별로 없습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[IAM]]></title>
            <link>https://velog.io/@jhanggun_kim/AWS-SAA-01.-IAM</link>
            <guid>https://velog.io/@jhanggun_kim/AWS-SAA-01.-IAM</guid>
            <pubDate>Sat, 05 Nov 2022 06:58:43 GMT</pubDate>
            <description><![CDATA[<p>IAM = Identity and Access Management
Region에 상관없는 글로벌 서비스.</p>
<p>AWS 어카운트를 만들면 루트 어카운트가 됩니다.</p>
<p>이 루트 어카운트는 유저를 만들 때만 쓰세요.</p>
<p>IAM으로 유저를 만들었으면 그룹에 넣을 수 있습니다.</p>
<p><strong>그룹에는 유저만 넣을 수 있습니다, 그룹 안에 그룹을 넣을 수 없습니다</strong>.</p>
<p>유저는 하나 이상의 그룹에 들어갈 수 있습니다.</p>
<p>다음으로는 권한을 주어야 합니다.</p>
<p>&#39;정책&#39;이라고 하는 JSON 문서로 유저 또는 그룹이 어떤 권한을 가지게 할 것인지 세팅할 수 있습니다.</p>
<p>AWS에서는 사고의 위험을 줄이기 위해 <strong>최소 권한 룰</strong>을 쓰고 있습니다.</p>
<p>즉 유저가 필요로 하는 것 이상의 권한은 주지 않습니다.</p>
<p>루트 어카운트만 모든 권한을 가지고 있습니다.</p>
<p>루트 어카운트는 이와 같이 룰을 어기기 때문에 AWS 서비스를 쓰는 어카운트로는 알맞지 않은 것입니다.</p>
<p>Admin 어카운트가 있어야 한다면 따로 유저를 만들고,</p>
<p>Admin 그룹을 만들고 AdministratorAccess 정책을 세팅해 주면 됩니다.</p>
<p>그리고 유저에게는 태그를 달 수 있는데, 이는 유저들의 액세스를 매니지먼트 및 컨트롤하기에 도움을 줍니다.</p>
<p>만들어진 유저로 로그인을 할 때는 아래와 같이 계정 ID(12자리) 또는 계정 별칭을 써야 합니다.
<img src="https://velog.velcdn.com/images/jhanggun_kim/post/19c606f4-d1dd-4bc3-8338-2fa0f03635ba/image.png" alt=""></p>
<p>이것들은 IAM 대시보드에서 볼 수 있습니다.</p>
<p>계정 별칭은 여러분이 정할 수 있으며, 12자리 계정 ID의 도메인 이름이라고 생각하면 됩니다.</p>
<hr>

<p><strong>IAM 롤</strong>이라는 것도 있는데, 이건 어떤 <strong>AWS 서비스에게 권한을 세팅</strong>하는 것입니다.</p>
<p>예를 들어 EC2에게 IAM에 대한 ReadOnly 권한을 줄 수 있습니다.</p>
<hr>

<p>정책에 대해 좀 더 알아보겠습니다.
정책은 어떤 유저나 그룹에게 줄 수 있습니다.</p>
<p>AWS에서 만들어 놓은 정책을 써도 되고, JSON 문서를 만들어도 됩니다.</p>
<p><span style="color: red"><strong>정책의 구조</strong></span>(JSON 문서)를 보겠습니다.</p>
<ul>
<li>Version: 정책 &#39;언어&#39;의 버전, 웬만하면 2012-10-17로 되어 있음.</li>
<li>Id: 선택사항.</li>
<li>Statement: 하나 이상 선언 가능.<ul>
<li>Sid: 선택사항.</li>
<li><span style="color: red">Effect</span>: This statement에 주어진 API에 액세스하는 것을 Allow or Deny.</li>
<li><span style="color: red">Action</span>: Allow 또는 Deny될 API 리스트.</li>
<li><span style="color: red">Resource</span>: 어떤 리소스에 대한 액션들인지.</li>
<li><span style="color: red">Principal</span>: 정책이 적용될 유저, accounts, 혹은 roles.</li>
<li>Condition: 선택사항, 해당 문장이 언제 적용될지.</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jhanggun_kim/post/08fd9d6e-e132-4ef2-8e72-1359eb606c47/image.png" alt=""></p>
<hr>

<p>유저와 그룹의 시큐리티도 신경 써야 합니다.</p>
<p>2가지 방법이 있습니다.</p>
<ol>
<li>패스워드 정책 세우기 (AWS에서 관련 기능을 제공함.)<ul>
<li>Minimum length 세팅, 대소문자 1개씩 넣기 같은 specific 타입 요구, IAM 유저가 패스워드를 바꿀 수 있도록 Allow or Deny 세팅, 패스워드 만료일 세팅. 썼던 패스워드 다시 못 쓰게 하기 등.</li>
</ul>
</li>
<li><span style="color: red">MFA</span><ul>
<li>AWS에서 반드시 쓰도록 권장.</li>
<li>패스워드에 더하여 당신의 디바이스에서 2차적으로 인증을 해야 함.</li>
<li>쓸 수 있는 디바이스: 가상 MFA 디바이스(Google Authenticator 등), U2F(Universal 2nd Factor) 보안 키(YubiKey 등), 하드웨어 키 Fob MFA 디바이스(이것도 물리적 장치) 등.</li>
</ul>
</li>
</ol>
<hr>

<p><strong>IAM 보안 도구</strong>로는 2가지가 있습니다.</p>
<ol>
<li><strong>IAM 자격 증명서</strong>는 accounts 레벨의 보안 도구입니다.
Accounts의 보안 관련 정보를 가지고 있습니다.
(유저가 언제 만들어졌고, 언제 마지막으로 로그인 했고, 언제 비밀번호를 바꿨고, MFA가 되어 있는지 등.)</li>
<li><strong>IAM 액세스 관리자</strong>는 유저 레벨의 보안 도구입니다.
유저가 최근 4시간 동안 어떤 AWS 서비스에 액세스했는지 볼 수 있습니다.
어떤 유저에 대해 권한이 알맞게 주어져 있는지 체크하기 좋습니다.</li>
</ol>
<hr>

<p>여러분이 만들었거나 AWS에 의해 관리되고 있는 정책을 테스트해 볼 수 있는 툴이 있습니다.</p>
<p>IAM Policy Simulator 툴이고 찾으면 바로 나오니 한 번 봐 보세요!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[GraphQL]]></title>
            <link>https://velog.io/@jhanggun_kim/GraphQL</link>
            <guid>https://velog.io/@jhanggun_kim/GraphQL</guid>
            <pubDate>Sat, 21 May 2022 04:15:47 GMT</pubDate>
            <description><![CDATA[<p>Nomad Coders YouTube 채널에서 우연히 봤는데 쉽게 잘 설명해 주셔서 좋았다.</p>
<hr />

<p>GraphQL은 하나의 아이디어고, 이를 스펙으로 만든 것이다.
다운로드 받는 것이 아님.</p>
<p>즉, 특정 언어에 종속되지 않는다.</p>
<hr />

<p>REST API의 문제(over fetching, under fetching)들을 해결하기 위해 만들어졌다.</p>
<p>Over Fetching
    - 필요한 데이터보다 많은 데이터를 가져오는 것.
    - 어떤 URL에 요청하여 JSON 문서로 다양한 데이터를 받았는데, 사실 그 중에 진짜 필요한 건 딱 하나의 키-값인 경우.
    - 이러면 DB가 쓸데없이 일을 많이 한 것이고 서버와 클라이언트 간의 데이터 전송량도 쓸데없이 많은 것. 따라서 로딩 시간이 쓸데없이 길어진다.</p>
<p>Under Fetching
    - 반대로 필요한 것보다 적은 데이터를 가져오는 경우를 말한다.
    - 어떤 페이지에 상영예정영화 리스트랑 현재상영영화 리스트를 보여 주고 싶다 하자.
    - REST API에서는 2개의 API를 호출해야 한다. /movie/upcoming, /movie/nowPlaying.
    - 왜 한 번의 API 호출로 필요한 데이터들을 모두 가져올 수 없는 것일까?
    - GraphQL에서는 가능하다.</p>
<p>결국 GraphQL의 장점은,
진짜 필요한 부분만 요청할 수 있다는 것.
이를 통해 프로그램의 성능을 올릴 수 있다.</p>
<hr />

<p>코멘트도 좀 봤는데, API로 파일 업로드 등의 파일 처리 시 문제가 있는 것으로 보이고
REST API를 좀 더 디테일하게 여러 개 두면 over fetching, under fetching 해결을 할 수 있지 않나 싶기도 하다.</p>
<p>그리고 아직 많은 사이트들(공공기관 등)이 REST API를 제공하고 있기 때문에, GraphQL을 잘 쓸 수 있는 것인지 의문이 든다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS Region & AZ]]></title>
            <link>https://velog.io/@jhanggun_kim/AWS-Region-AZ</link>
            <guid>https://velog.io/@jhanggun_kim/AWS-Region-AZ</guid>
            <pubDate>Tue, 10 May 2022 15:32:35 GMT</pubDate>
            <description><![CDATA[<p>AWS region의 정의를</p>
<p><strong>데이터 센터</strong>(IDC, International Data Corporation)<strong>의 집합</strong>이라고 말할 수 있다.</p>
<p>그리고 AWS에 region들 여러 개가 있는 건 알고 있었는데,</p>
<p>AZ가 가용영역이란 것까지만 생각이 나고 더 깊은 얘기가 생각이 안 나서 아쉽다.</p>
<p>위 얘기들을 보았을 때 하나의 <strong>AZ</strong>가 하나의 <strong>IDC</strong>임을 알 수 있을 것이다.</p>
<p style="color: gray">
사실 하나의 AZ가 서로 네트워크로 이어진 두 IDC의 세트인 경우도 있지만,
</p>

<p style="color: gray">
AWS에서 이런 데이터를 오픈하는 것도 아니고 뭐 중요한 것도 아니라.
</p>

<p>어쨌든 이렇게 AZ를 쪼개고, IDC를 쪼개는 것은 재난에 대비하는 거다.</p>
<p>그리고 한 region에 있는 여러 AZ는 높은 대역폭, 낮은 지연의 네트워크로 이어져 있다.</p>
<hr>

<p>AWS 대부분의 서비스들은 region별로 딸려 있다.</p>
<p>예를 들어 서울 region에 여러 서비스를 쓰고 있더라도</p>
<p>미국 region에서 같은 서비스들을 쓰면 처음 쓰는 것처럼 되어 있다는 것.</p>
<p>관련 리스트는 AWS Global Infrastructure의 <a href="https://aws.amazon.com/ko/about-aws/global-infrastructure/regional-product-services/?p=ngi&amp;loc=4">AWS Regional Services</a>에서 볼 수 있다.</p>
<hr>

<p>프랑스 region의 AWS 서비스들은 프랑스의 법을 지켜야 한다.</p>
<p>위 예처럼 어떤 region의 AWS 서비스들을 쓸 땐 나라의 법을 아는 게 좋을 것이다.</p>
<p>또한 region에 따라 제공하는 AWS 서비스의 수에 차이가 있다.</p>
<p>그리고 region에 따라 요금도 다르니 봐 두어야 하고.</p>
<hr>

<p>글로벌 인프라 관점에서, <strong>에지 로케이션</strong>에 대해서도 알아 두면 좋다.</p>
<p>여러 나라, 여러 도시에 걸쳐 총 200개가 넘는 에지 로케이션이 있다.</p>
<p>이를 통해 지연시간을 낮춰 유저에게 콘텐츠를 쉽게 보낼 수 있다.</p>
]]></description>
        </item>
    </channel>
</rss>