<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://daniazie.github.io/ms/feed.xml" rel="self" type="application/atom+xml" /><link href="https://daniazie.github.io/ms/" rel="alternate" type="text/html" /><updated>2026-04-29T19:45:58+09:00</updated><id>https://daniazie.github.io/feed.xml</id><title type="html">Dania Moriazi</title><subtitle>A Malaysian student studying Software Convergence at Kyung Hee University.</subtitle><entry><title type="html">[수학 공부] Why Machines Learn 2주차: Gradients</title><link href="https://daniazie.github.io/ms/posts/Why-Machines-Learn-2/" rel="alternate" type="text/html" title="[수학 공부] Why Machines Learn 2주차: Gradients" /><published>2025-10-01T00:00:00+09:00</published><updated>2025-10-01T00:00:00+09:00</updated><id>https://daniazie.github.io/posts/Why-Machines-Learn-2</id><content type="html" xml:base="https://daniazie.github.io/posts/Why-Machines-Learn-2/"><![CDATA[<h2 id="공지사항">공지사항</h2>
<ul>
  <li>이번 주부터 영어로 함</li>
</ul>

<h2 id="the-basics-of-calculus">The Basics of Calculus</h2>

<p>Given a curve, we can use the tangent at any given point to find the slope of the curve. To find the tangent, we divide the change in $y$ by the change in $x$, 
\(\frac{\Delta y}{\Delta x}\)</p>

<p>where $\Delta$ represents a very small change in a given value. However, this would correspond to the movement <em>along the tangent</em> as opposed to along the slope. However, as the changes in $x$, $\Delta x$, approaches 0, the tangent line also approaches th slope until the tangent and the slope are the same at $\Delta x = 0$.</p>

<p>Here is where the problem comes in: … how do we divide a value (in this case, $\Delta y$) by 0? This is where calculus comes in. Calculus allows us to calculate the ratio of the changes in two values even as the term approaches zero.</p>

<p>Specifically, $\frac{dy}{dx}$ is a little bit of $y$ divided by a little bit of $x$, and calculus allows us to calculate this ratio even when $dx \rightarrow 0$</p>

<h2 id="gradient-descent">Gradient Descent</h2>

\[x_\text{new} = x_\text{old} - \eta\cdot\text{gradient}\]

\[y_\text{new} = x_\text{new}^2\]

<p>What we aim to do here is minimise $x$ in order to move down the gradient. $\eta$ is some fraction that represents how far along the gradient do we want to move (step size). That is, we want to find the global minimum.</p>

<h4 id="caution">Caution!!</h4>
<ul>
  <li>Some functions such as a hyperbolic paraboloid function ($z = y^2 - x^2$) do not have a minimum. These functions are often unstable due to its saddle point <del>세션 때 안 그려드리면 편하게 혼내세요</del>, where by one false step might cause you to fall off the hyperplane.</li>
</ul>

<p>For a 3-D function, we need partial derivatives. Given \(z = x^2 + y^2,\) we need find the partial derivatives of $z$. In this case, they are: \(\frac{\delta{z}}{\delta{x}} = 2x, \frac{\delta{z}}{\delta{y}} = 2y.\)</p>

<p>By calculating $2x$ and $2y$, you get a vector, which informs us the direction directly opposite to the steepest descent. The main takeaway is is that for a multidimensional function, the gradient is given by a vector. Given our elliptical paraboloid, its gradient would be written as:</p>

\[\begin{bmatrix}\delta z/ \delta x \\ \delta{z} /\delta{y}\end{bmatrix} = \begin{bmatrix}2x \\ 2y\end{bmatrix} or \begin{bmatrix}2x &amp; 2y\end{bmatrix}\]

<p>Reorganising the above equations, we get the following weight update rule: \(\mathbf{w}_\text{new} = \mathbf{w}_\text{old} + \mu (-\nabla), \text{where } \mu = \text{step size, } \nabla=\text{gradient}\)</p>

<p>However, with a large number of features, finding the gradient would be computatinally expensive, if not impossible. Thus, we estimate the gradient so that the update rule becomes:</p>

\[\mathbf{w}_\text{new} = \mathbf{w}_\text{old} + 2\mu\epsilon\mathbf{x} \text{ where, }\]

\[\mu = \text{step size}\]

\[\epsilon = \text{error based on one data point},\]

\[\mathbf{x} = \text{the vector representing a single data point}\]

<p>The error is given by:</p>

\[\epsilon = d - \mathbf{w}\top\mathbf{x}, \text{where } d = \text{target}\]

<p>And through this, we get the least mean squares algorithm.</p>]]></content><author><name></name></author><category term="Study" /><category term="수학" /><category term="KHUDA" /><summary type="html"><![CDATA[공지사항 이번 주부터 영어로 함]]></summary></entry><entry><title type="html">[수학 공부] Why Machines Learn 1주차: The Perceptron</title><link href="https://daniazie.github.io/ms/posts/Why-Machines-Learn-1/" rel="alternate" type="text/html" title="[수학 공부] Why Machines Learn 1주차: The Perceptron" /><published>2025-09-09T00:00:00+09:00</published><updated>2025-09-09T00:00:00+09:00</updated><id>https://daniazie.github.io/posts/Why-Machines-Learn-1</id><content type="html" xml:base="https://daniazie.github.io/posts/Why-Machines-Learn-1/"><![CDATA[<h2 id="개요">개요</h2>
<p>KHUDA 자연언어처리 트랙 뒷타임 수학 세션은 Anil Ananthaswamy가 쓰신 Why Machines Learn: The Elegant Math Behind Modern AI라는 책을 다룹니다. 책 내용을 번역하여 정리하고 뒷타임 세션 때 강의해드립니다. 그리고 욕심이 엄청 높아져서 해당 책에서 공부하는 수학을 코드로 응용하는 것도 해보겠습니다.</p>

<h2 id="내용-정리---교재-1장과-2장">내용 정리 - 교재 1장과 2장</h2>
<h3 id="지도학습">지도학습</h3>

\[y = w_1x_1 + w_2x_2 + \cdots +w_nx_n = \sum_{i=1}^n w_ix_i\]

<p>을 가정합시다. 수학적으로 지도학습은 각 가중치 $w_i$를 추출하도록 학습하는 목표입니다. 즉, 특징 (features)와 타겟값의 관계를 분석하는 것입니다.</p>

<p>${x, y}$를 가지는 데이터를 훈련데이터하고 하는데 labeled data 또는 annotated data라고도 합니다.</p>

<blockquote><dl><dt>노트!<br />
<dd>지연언어처리 논문에서 보통 annotated data라고 합니다</dd>
</dt></dl></blockquote>

<h3 id="첫-인공-뉴런">첫 인공 뉴런</h3>
<p><strong>McCulloch-Pitts (MCP) 뉴런:</strong> 계산 단위인데, 계산만 가능하고 학습 불가능 → Rosenblatt’s Perceptron</p>

\[\begin{aligned}g(x) &amp; = x_1 + x_2+\cdots+x_n \\ f(z) &amp; =  \begin{cases} 0, z &lt; \theta \\ 1, z \geq \theta \end{cases} \\ y = f(g(x)) &amp; = \begin{cases} 0, g(x) &lt; \theta \\ 1, g(x) \geq \theta \end{cases} \end{aligned}\]

<h3 id="실수로써-학습하기">실수로써 학습하기</h3>
<h4 id="학습이란">학습이란</h4>
<ul>
  <li><strong>인공 모델:</strong> 데이터를 분석하면서 패턴을 추출하기</li>
  <li><strong>인간:</strong> 한 뉴런의 아웃풋이 다른 뉴런을 트리거할 때는 뉴런 간의 연결을 강화하는 과정 → Hebbian Learning이라고 함</li>
</ul>

<p>→ Rosenblatt은 인간의 뉴런과 같이 서로 트리거함으로써 공부하는 인공 뉴런을 발전하고자 하셨습니다.</p>

<h4 id="augmented-mcp-퍼셉트론">Augmented MCP (퍼셉트론)</h4>
<ul>
  <li>데이터에 없는 샘플의 값을 알 수 있도록 데이터 특징과 레이블 간 관계를 학습하기</li>
</ul>

\[\begin{align}g(x) &amp; = w_1x_1 + w_2x_2 + \cdots + w_nx_n + b = \sum_{i=1}^{n}w_ix_i + b \\ f(z) &amp; = \begin{cases}-&amp;1, z \leq 0 \\ &amp; 1, z &gt; 0\end{cases} \\ y = f(g(x)) &amp; = \begin{cases} - &amp; 1, g(x) \leq 0 \\ &amp; 1, g(x) &gt; 0\end{cases}\end{align}\]

<p><strong>벡터로 표현하려면</strong></p>

\[y = \begin{cases} - &amp; 1, \mathbf{w}^\top\mathbf{x} \leq 0 \\ &amp; 1, \mathbf{w}^\top\mathbf{x} &gt; 0 \end{cases}, \text{ where } \mathbf{w} = \{w_0, w_1, \cdots, w_n\} \text{ and } \mathbf{x} = \{1, x_1, \cdots, x_n\}\]

<p><strong>파라미터 업데이트</strong></p>

\[\mathbf{w}_{\text{new}} = \mathbf{w}_\text{old} + y\mathbf{x} \text{ if } y\mathbf{w}^\top\mathbf{x} \leq 0\]

<blockquote>
  <p><strong>왜 $y\mathbf{w}^\top\mathbf{x}$인가?</strong><br />
$y$과 $\mathbf{w}^\top\mathbf{x}$가, 즉 실제값과 예측값이, 똑같으면 스칼라곱은 양수고, 예측값이 틀리면 음수가 나와서 잘 예측한지 확인하도록 스칼라곱 과정을 진행합니다.<br /> <br />
→ 즉, 데이터와 적합하는 가중치와 편향을 알아보는 목표입니다</p>
</blockquote>

<table>
  <thead>
    <tr>
      <th>MCP</th>
      <th>Perceptron</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>인풋은 이진값이어야 함</td>
      <td>인풋은 이진값이 아닌 값을 가져도 됨</td>
    </tr>
    <tr>
      <td>가중치 없음</td>
      <td>가중치 有</td>
    </tr>
    <tr>
      <td>아웃풋은 0이나 1임</td>
      <td>아웃풋은 -1이나 1임</td>
    </tr>
    <tr>
      <td>학습 불가</td>
      <td>가중치와 편향을 학습 가능</td>
    </tr>
  </tbody>
</table>

<h2 id="파이썬으로-응용하기">파이썬으로 응용하기</h2>
<p>자… 위 개념을 기반으로 퍼셉트론 직접 만들어봅시다.</p>

<blockquote>
  <p>참고: <a href="https://colab.research.google.com/drive/1GdTKzX7ulZOretLsK4IqmEVaf-ku3m5O?usp=sharing">Colab</a></p>
</blockquote>

<p>해당 실습은 numpy를 이용합니다.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>우리는 Perceptron이라는 파이썬 클래스를 만들고 클래스 속 함수를 정의합니다.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
</pre></td><td class="rouge-code"><pre><span class="k">class</span> <span class="nc">Perceptron</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span>
            <span class="n">self</span><span class="p">,</span> 
            <span class="n">inputs</span><span class="p">,</span> 
            <span class="n">labels</span><span class="p">,</span> 
            <span class="n">epoch</span><span class="p">,</span>
        <span class="c1">#    learning_rate = 0.05
</span>            <span class="p">):</span>

        <span class="sh">"""</span><span class="s">
        클래스 초기화하는 함수
        
        self를 통해 </span><span class="sh">'</span><span class="s">이 클래스가 원래 요 변수들을 갖는다</span><span class="sh">'</span><span class="s">라고 정할 수 있습니다. 
        해당 코드는 bias를 w[0]로 정의하여, 인풋 배열에 x[0]=1 산입합니다  (즉, [1, x1, x2])

        그리고, 교재에서 learning rate 아직도 안 나타났지만, learning rate 어떻게 적용할지를 아실  수 있도록 주석으로 learning rate에 해당 코드를 놓았습니다.
        </span><span class="sh">"""</span>

        <span class="n">self</span><span class="p">.</span><span class="n">inputs</span> <span class="o">=</span> <span class="n">inputs</span>
        <span class="n">self</span><span class="p">.</span><span class="n">inputs</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([</span><span class="n">np</span><span class="p">.</span><span class="nf">insert</span><span class="p">(</span><span class="n">inp</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="k">for</span> <span class="n">inp</span> <span class="ow">in</span> <span class="n">inputs</span><span class="p">])</span>
        <span class="n">self</span><span class="p">.</span><span class="n">weights</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">zeros</span><span class="p">(</span><span class="nf">len</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">inputs</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span>
        <span class="n">self</span><span class="p">.</span><span class="n">labels</span> <span class="o">=</span> <span class="n">labels</span>
        <span class="n">self</span><span class="p">.</span><span class="n">epoch</span> <span class="o">=</span> <span class="n">epoch</span>
        <span class="c1"># self.lr = learning_rate
</span>        
    <span class="k">def</span> <span class="nf">step_function</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">product</span><span class="p">):</span>
        <span class="sh">"""</span><span class="s">
        이진 분류 실행하는 계단함수 코드
        </span><span class="sh">"""</span>
        <span class="k">if</span> <span class="n">product</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">return</span> <span class="o">-</span><span class="mi">1</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="mi">1</span>

    <span class="k">def</span> <span class="nf">update</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">weights</span><span class="p">,</span> <span class="n">inputs</span><span class="p">,</span> <span class="n">labels</span><span class="p">):</span>
        <span class="sh">"""</span><span class="s">
        가중치 업데이트
        </span><span class="sh">"""</span>
        <span class="k">return</span> <span class="n">weights</span> <span class="o">+</span> <span class="n">labels</span><span class="o">*</span><span class="n">inputs</span>

    <span class="k">def</span> <span class="nf">train</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="sh">"""</span><span class="s">
        훈련 코드

        epoch마다 각 샘플에 대한 y</span><span class="sh">'</span><span class="s">를 계산하고, 필요하면 파라미터 업데이트 실행합니다.
        </span><span class="sh">"""</span>
        <span class="n">epoch</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">epoch</span>

        <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">epoch</span><span class="p">):</span>
            <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">tqdm</span><span class="p">(</span><span class="nf">range</span><span class="p">(</span><span class="nf">len</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">inputs</span><span class="p">)),</span> <span class="n">desc</span><span class="o">=</span><span class="sa">f</span><span class="sh">'</span><span class="s">Epoch </span><span class="si">{</span><span class="n">e</span><span class="o">+</span><span class="mi">1</span><span class="si">}</span><span class="sh">'</span><span class="p">):</span>
                <span class="n">pred</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">weights</span> <span class="o">@</span> <span class="n">self</span><span class="p">.</span><span class="n">inputs</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
                <span class="n">acc</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="nf">step_function</span><span class="p">(</span><span class="n">pred</span><span class="p">)</span> <span class="o">*</span> <span class="n">self</span><span class="p">.</span><span class="n">labels</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
                <span class="k">if</span> <span class="n">acc</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">:</span>
                    <span class="n">self</span><span class="p">.</span><span class="n">weights</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="nf">update</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">weights</span><span class="p">,</span> <span class="n">self</span><span class="p">.</span><span class="n">inputs</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">self</span><span class="p">.</span><span class="n">labels</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
                <span class="c1">#   self.weights = self.weights + self.lr * (self.labels[i] * self.inputs[i])
</span>    
    <span class="k">def</span> <span class="nf">predict</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">inputs</span><span class="p">):</span>
        <span class="sh">"""</span><span class="s">
        예측 코드

        추출된 가중치를 통해 실험 셋의 레이블을 계산합니다.
        </span><span class="sh">"""</span>
        <span class="n">weights</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">weights</span>
        <span class="n">inputs</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([</span><span class="n">np</span><span class="p">.</span><span class="nf">insert</span><span class="p">(</span><span class="n">inp</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="k">for</span> <span class="n">inp</span> <span class="ow">in</span> <span class="n">inputs</span><span class="p">])</span>
        <span class="n">product</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([</span><span class="n">weights</span> <span class="o">@</span> <span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">inputs</span><span class="p">])</span>
        <span class="n">pred</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([</span><span class="n">self</span><span class="p">.</span><span class="nf">step_function</span><span class="p">(</span><span class="n">pred</span><span class="p">)</span> <span class="k">for</span> <span class="n">pred</span> <span class="ow">in</span> <span class="n">product</span><span class="p">])</span>

        <span class="k">return</span> <span class="n">pred</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="보너스-기초-평가-방법들">보너스: 기초 평가 방법들</h3>

<p>나중 6주차 때 평가에 대해 공부할 테지만, 그래도 자연언어처리에 사용하는 평가의 기초 공식을 간략하게 공부하면 좋지 않을까 싶었습니다.</p>

<h4 id="accuracy">Accuracy</h4>
<p>제일 기분 공식은 정확성(Accuracy)라고, 전체 샘플에 비해 모델을 어느 정도 잘 맞추는지를 알려주는 공식입니다. 즉,</p>

\[\text{Accuracy} = \frac{\text{Correct Predictions}}{\text{Total Samples}}\]

<p>코드로:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">def</span> <span class="nf">evaluate</span><span class="p">(</span><span class="n">pred_labels</span><span class="p">,</span> <span class="n">label</span><span class="p">):</span>
    <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">for</span> <span class="n">pred</span><span class="p">,</span> <span class="n">true</span> <span class="ow">in</span> <span class="nf">zip</span><span class="p">(</span><span class="n">pred_labels</span><span class="p">,</span> <span class="n">label</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">pred</span> <span class="o">==</span> <span class="n">true</span><span class="p">:</span>
            <span class="n">count</span> <span class="o">+=</span> <span class="mi">1</span>
    <span class="k">return</span> <span class="n">count</span><span class="o">/</span><span class="nf">len</span><span class="p">(</span><span class="n">pred_labels</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>하지만, 클래스 불균형이 있으면 단순히 Accuracy를 이용하면 불확실한 결과도 나올 수도 있습니다.</p>

<p>따라서, confusion matrix를 이용하는 평가 공식을 이용합니다.</p>

<h4 id="le-confusion-matrix">Le Confusion Matrix</h4>

<p>예측값은 4가지로 분류될 수 있습니다. 첫번째 경우 true positive이라고 잘 예측된 positive한 레이블, 두번째는 true negative이라고 잘 예측된 negative한 레이블, 셋번째 false positive이라고 못 맞추는 negative한 레이블, 그리고 false negative이라고 못 맞추는 positive한 레이블. 즉,</p>

<table>
  <thead>
    <tr>
      <th>Pred/True</th>
      <th>Positive</th>
      <th>Negative</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Positive</strong></td>
      <td>TP</td>
      <td>FP</td>
    </tr>
    <tr>
      <td><strong>Negative</strong></td>
      <td>FN</td>
      <td>TN</td>
    </tr>
  </tbody>
</table>

<p>따라서, confusion matrix를 이용해 정확성을 다시 정의하려면,</p>

\[\text{Accuracy} = \frac{\text{TP} + \text{TN}}{\text{TP} + \text{TN} + \text{FP} + \text{FN}}\]

<p>즉, 단순히 모델은 어느 정도 잘 맞추느냐를 나타내는 공식입니다.</p>

<h4 id="관련성-relevance">관련성 (Relevance)</h4>

<p>관련성은 모델이 얼마 정도로 우리가 원하는 정보를 추출하는지를 알려주는 평가방법입니다. 관련성 기반 평가 계산은 크게 3가지 있습니다.</p>

<p><strong>Precision</strong></p>

<p>Precision은 모델이 positive하는 것으로 예측하는 샘플에 비해 올바르게 positive하는 것을 예측하는 값이 나타납니다. 즉,</p>

\[\text{Precision} = \frac{TP}{\text{TP} + \text{FP}}\]

<p><strong>Recall</strong></p>

<p>Recall은 실제 positive 값 샘플에 비해 모델이 올바르게 예측하는 positive값 얼마인지를 나타내는 값입니다. 즉,</p>

\[\text{Recall} = \frac{TP}{\text{TP} + \text{FN}}\]

<p><strong>Precision vs. Recall</strong></p>

<p>Precision과 Recall 중에 어떤 걸로 사용하면 더 나을까요? 정답은 케이스바이케이스입니다.</p>

<p>FP 줄이도록 하고자 하면 Precision 이용하면 더 낫고 FN 줄이도록 하고자 하면 Recall 이용하면 더 좋죠. 예를 들어 암 검사에서 FP 나타나면 환자에게 비용이 많아지며 FP를 줄도록 평가하면 더 좋고, 피슁이 발생하면 정말 大 일 나겠어 Recall 위주로 평가하면 제일 베스트죠.</p>

<p><strong>$F_1$ 점수</strong></p>

<p>$F_1$ 점수는 Precision과 Recall 같이 계산하는 평가방법인데, $\beta=1$인 $F_\beta$ 점수 나타납니다. $\beta$는 가중치이므로 $\beta=1$이라면 Precision과 Recall을 대칭으로 대표해 계산합니다. 즉, Precision과 Recall 조화 평균(harmonic mean)을 나타냅니다.</p>

\[F_\beta = \frac{(1+\beta^2)\cdot\text{precision}\cdot\text{recall}}{\beta^2\cdot\text{precision}+\text{recall}}\]

<p>$\beta &gt; 1$라면, $w_\text{recall} &gt; w_\text{precision}$이라고 생각해도 되고 $\beta &lt; 1$ 경우 $w_\text{recall} &lt; w_\text{precision}$이라고 생각해도 됩니다. 즉, $\beta =1$일 때,  $w_\text{recall} = w_\text{precision}$입니다.</p>

\[\begin{align*} \beta &amp; = 1, \\ F_1 &amp; = 2\cdot\frac{\text{precision}\cdot\text{recall}}{\text{precision} + \text{recall}} = \frac{2\text{TP}}{2\text{TP}+\text{FP}+\text{FN}}\end{align*}\]

<blockquote>
  <p>노트!
LLM 평가할 때 $F_1$ 위주로 이용합니다.</p>
</blockquote>]]></content><author><name></name></author><category term="Study" /><category term="수학" /><category term="KHUDA" /><summary type="html"><![CDATA[개요 KHUDA 자연언어처리 트랙 뒷타임 수학 세션은 Anil Ananthaswamy가 쓰신 Why Machines Learn: The Elegant Math Behind Modern AI라는 책을 다룹니다. 책 내용을 번역하여 정리하고 뒷타임 세션 때 강의해드립니다. 그리고 욕심이 엄청 높아져서 해당 책에서 공부하는 수학을 코드로 응용하는 것도 해보겠습니다.]]></summary></entry><entry><title type="html">도커와 쿠버네티스 10: 쿠버네티스를 활용한 웹 서비스 배포</title><link href="https://daniazie.github.io/ms/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A410/" rel="alternate" type="text/html" title="도커와 쿠버네티스 10: 쿠버네티스를 활용한 웹 서비스 배포" /><published>2024-09-03T00:00:00+09:00</published><updated>2024-09-03T00:00:00+09:00</updated><id>https://daniazie.github.io/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A410</id><content type="html" xml:base="https://daniazie.github.io/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A410/"><![CDATA[<h2 id="사전-준비-사항">사전 준비 사항</h2>
<h3 id="postgresql-확인">PostgreSQL 확인</h3>
<ul>
  <li>PostgreSQL이 가동 중인지 확인 <img src="/assets/img/posts/docker10/img1.png" alt="photo 1" /></li>
</ul>

<h2 id="인그레스를-활용한-django-실행">인그레스를 활용한 django 실행</h2>
<h3 id="디렉터리-정리">디렉터리 정리</h3>
<ul>
  <li>디렉터리를 아래와 같이 정리한다 <img src="/assets/img/posts/docker10/img2.png" alt="photo 2" /></li>
</ul>

<h3 id="django-이미지-빌드">django 이미지 빌드</h3>
<ul>
  <li>myDjango04/myapp/myapp에 있는 settings.py를 수정한다 <img src="/assets/img/posts/docker10/img3.png" alt="photo 3" /></li>
  <li>아래와 같이 이미지를 빌드한다 <img src="/assets/img/posts/docker10/img4.png" alt="photo 4" /></li>
  <li>도커 이미지 목록 확인 <img src="/assets/img/posts/docker10/img5.png" alt="photo 5" /></li>
  <li>도커 리포지토리를 생성하겠는데 일단 터미널에서 로그인하겠다 <img src="/assets/img/posts/docker10/img6.png" alt="photo 6" /></li>
  <li>태그를 생성하고 업로드한다 <img src="/assets/img/posts/docker10/img7.png" alt="photo 7" /></li>
  <li>도커 허브 홈페이지에 확인 <img src="/assets/img/posts/docker10/img8.png" alt="photo 8" /></li>
</ul>

<h3 id="nginx-이미지-빌드">Nginx 이미지 빌드</h3>
<ul>
  <li>MyNginx04d에 있는 default.conf를 아래와 같이 수정한다 <img src="/assets/img/posts/docker10/img9.png" alt="photo 9" /></li>
  <li>이미지 빌드 <img src="/assets/img/posts/docker10/img10.png" alt="photo 10" /></li>
  <li>이미지 목록 확인 <img src="/assets/img/posts/docker10/img11.png" alt="photo 11" /></li>
  <li>도커 허브에서 리포지토리를 생성 <img src="/assets/img/posts/docker10/img12.png" alt="photo 12" /></li>
  <li>아래와 같이 태그하고 업로드한다 <img src="/assets/img/posts/docker10/img13.png" alt="photo 13" /></li>
  <li>도커 허브 확인 <img src="/assets/img/posts/docker10/img14.png" alt="photo 14" /></li>
</ul>

<h3 id="디플로이먼트-실습">디플로이먼트 실습</h3>
<ul>
  <li>ex01에서 django-deploy.yml를 아래와 같이 작성한다 <img src="/assets/img/posts/docker10/img15.png" alt="photo 15" /></li>
  <li>디플로이먼트 파일 실행 <img src="/assets/img/posts/docker10/img16.png" alt="photo 16" /></li>
  <li>파드 확인 <img src="/assets/img/posts/docker10/img17.png" alt="photo 17" />
    <ul>
      <li>오류 나왔는데 못 풀어서 일단 바로 11장을 시작하겠습니다……</li>
    </ul>
  </li>
</ul>]]></content><author><name></name></author><category term="Study" /><category term="Docker &amp; Kubernetes" /><category term="KHUDA" /><summary type="html"><![CDATA[사전 준비 사항 PostgreSQL 확인 PostgreSQL이 가동 중인지 확인]]></summary></entry><entry><title type="html">도커와 쿠버네티스 11: 깃허브 액션과 ArgoCD를 활용한 CI/CD</title><link href="https://daniazie.github.io/ms/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A411/" rel="alternate" type="text/html" title="도커와 쿠버네티스 11: 깃허브 액션과 ArgoCD를 활용한 CI/CD" /><published>2024-09-03T00:00:00+09:00</published><updated>2024-09-03T00:00:00+09:00</updated><id>https://daniazie.github.io/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A411</id><content type="html" xml:base="https://daniazie.github.io/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A411/"><![CDATA[<h2 id="cicd의-이해">CI/CD의 이해</h2>
<ul>
  <li>Continuous Integration: 개발자가 코드를 지속적으로 통합하고 테스트하는 프로세스
    <ul>
      <li>소프트웨어를 개발하면서 개발자는 코드를 작성한 후에 깃과 같은 버전 관리 시스템에 push하게 되는데 이때 CI 소프트웨어는 새로운 코드를 기존 코드와 통합하고 자동으로 테스트한다</li>
    </ul>
  </li>
  <li>Continuous Deployment: 지속적 전달 도는 지속적 배포라는 뜻
    <ul>
      <li>지속적 전달: 코드를 배포할 수 이쓴 환경을 준비하는 과정까지</li>
      <li>지속적 배포: 실제로 코드를 배포하는 것까지
  → 교재에서 지속적 전달을 의미</li>
    </ul>
  </li>
</ul>

<h2 id="사전-준비-사항">사전 준비 사항</h2>
<ul>
  <li>metalLB가 설치되어 있는지 확인 <img src="/assets/img/posts/docker11/img1.png" alt="photo 1" /></li>
  <li>mymetallb 네임스페이스 확인 <img src="/assets/img/posts/docker11/img2.png" alt="photo 2" /></li>
</ul>

<h3 id="깃-설치">깃 설치</h3>
<ul>
  <li>아래와 같이 깃을 설치한다 <img src="/assets/img/posts/docker11/img3.png" alt="photo 3" /></li>
  <li>이름과 이메일 주소를 설정한다 <img src="/assets/img/posts/docker11/img4.png" alt="photo 4" /></li>
  <li>work에서 깃을 초기화한다 <img src="/assets/img/posts/docker11/img5.png" alt="photo 5" /></li>
</ul>

<h3 id="깃허브-액션을-통한-소스코드-관리">깃허브 액션을 통한 소스코드 관리</h3>
<h3 id="깃허브-액션을-사용한-hello-world-출력">깃허브 액션을 사용한 Hello World! 출력</h3>
<ul>
  <li>github-actions-practice라는 리포지토리를 생성하여 Actions 택으로 들어간다 <img src="/assets/img/posts/docker11/img6.png" alt="photo 6" /></li>
  <li>set up a workflow yourself을 선택한 후 아래와 같이 작성한다 <img src="/assets/img/posts/docker11/img7.png" alt="photo 7" /></li>
  <li>.github/workflows에서 확인할 수 있고 Actions 탭에 들어가면 아래와 같이 확인할 수 있다 <img src="/assets/img/posts/docker11/img8.png" alt="photo 8" /></li>
  <li>디렉터리를 아래와 같이 정리한다 <img src="/assets/img/posts/docker11/img9.png" alt="photo 9" /></li>
  <li>아래 창에서 링크를 복사한다 <img src="/assets/img/posts/docker11/img10.png" alt="photo 10" /></li>
  <li>아래와 같이 로컬에서 복제할 수 있다 <img src="/assets/img/posts/docker11/img11.png" alt="photo 11" /></li>
  <li>성공되는지 확인 <img src="/assets/img/posts/docker11/img12.png" alt="photo 12" /></li>
  <li>main.yml 확인 <img src="/assets/img/posts/docker11/img13.png" alt="photo 13" /></li>
</ul>

<h3 id="깃허브-액션을-통한-도커-컨테이너-실행">깃허브 액션을 통한 도커 컨테이너 실행</h3>
<ul>
  <li>github-actions-practice에서 Dockerfile을 생성하여 작성한다 <img src="/assets/img/posts/docker11/img14.png" alt="photo 14" /></li>
  <li>requirements.txt를 아래와 같이 작성한다 
  <img src="/assets/img/posts/docker11/img15.png" alt="photo 15" /></li>
  <li>myapp 폴더를 생성한 후 아래와 같이 main.py를 작성한다 <img src="/assets/img/posts/docker11/img16.png" alt="photo 16" /></li>
  <li>.github/workflows에서 flask-test.yml을 아래와 같이 작성한다 <img src="/assets/img/posts/docker11/img17.png" alt="photo 17" /></li>
  <li>아래와 같이 정보를 확인한다 <img src="/assets/img/posts/docker11/img18.png" alt="photo 18" /></li>
  <li>아래와 같이 깃허브로 push한다 <img src="/assets/img/posts/docker11/img19.png" alt="photo 19" />
    <ul>
      <li>이제 비밀번호로 로그인하면 안 된다고 해서 링크를 따르고 성공 <img src="/assets/img/posts/docker11/img20.png" alt="photo 20" /></li>
    </ul>
  </li>
</ul>

<h3 id="argocd를-활용한-cd">ArgoCD를 활용한 CD</h3>
<ul>
  <li>ArgoCD: 쿠버네티스 애플리케이션의 자동 배포를 가능하게 해주는 오픈소스 소프트웨어</li>
</ul>

<h3 id="argocd-설치">ArgoCD 설치</h3>
<ul>
  <li>헬름을 활용하여 argocd 리포지토리를 추가한다 <img src="/assets/img/posts/docker11/img21.png" alt="photo 21" />
    <ul>
      <li>그 중에서 argo/argo-cd 설치 예정</li>
    </ul>
  </li>
  <li>디렉터리 정리 <img src="/assets/img/posts/docker11/img22.png" alt="photo 22" /></li>
  <li>argo/argo-cd pull한다 <img src="/assets/img/posts/docker11/img23.png" alt="photo 23" /></li>
  <li>네임스페이스를 생성하고 네임스페이스 목록 확인 <img src="/assets/img/posts/docker11/img24.png" alt="photo 24" /></li>
  <li>네임스페이스 설치 <img src="/assets/img/posts/docker11/img25.png" alt="photo 25" /></li>
  <li>네임스페이스 확인 <img src="/assets/img/posts/docker11/img26.png" alt="photo 26" /></li>
  <li>argocd 서비스에 접근할 수 있도록 ClusterIP에서 LoadBalancer 타입으로 변경한다 <img src="/assets/img/posts/docker11/img27.png" alt="photo 27" /></li>
  <li>바뀐지 확인 <img src="/assets/img/posts/docker11/img28.png" alt="photo 28" /></li>
  <li>비밀번호 확인 <img src="/assets/img/posts/docker11/img29.png" alt="photo 29" /></li>
  <li>나오는 IP 주소를 포트포워딩에 추가한다 <img src="/assets/img/posts/docker11/img30.png" alt="photo 30" /></li>
  <li>127.0.0.1:2001에 접속해본다 <img src="/assets/img/posts/docker11/img31.png" alt="photo 31" /> <img src="/assets/img/posts/docker11/img32.png" alt="photo 32" /></li>
</ul>

<h3 id="argocd를-활용한-깃허브-실습">ArgoCD를 활용한 깃허브 실습</h3>
<ul>
  <li>깃허브 리포지토리 생성 <img src="/assets/img/posts/docker11/img33.png" alt="photo 33" /></li>
  <li>디렉터리 정리 <img src="/assets/img/posts/docker11/img34.png" alt="photo 34" /></li>
  <li>deployment.yml 작성 <img src="/assets/img/posts/docker11/img35.png" alt="photo 35" /></li>
  <li>service.yml 작성 <img src="/assets/img/posts/docker11/img36.png" alt="photo 36" /></li>
  <li>깃 초기화 <img src="/assets/img/posts/docker11/img37.png" alt="photo 37" /></li>
  <li>로컬 리포지토리와 깃허브 리포지토리를 연결하고 깃허브로 업로드한다 <img src="/assets/img/posts/docker11/img38.png" alt="photo 38" /></li>
  <li>argocd로 돌아와서 리포지토리를 연결한다 <img src="/assets/img/posts/docker11/img39.png" alt="photo 39" /></li>
  <li>연결되었는지 확인 <img src="/assets/img/posts/docker11/img40.png" alt="photo 40" /></li>
  <li>아래와 같이 새로운 애플리케이션을 만든다 <img src="/assets/img/posts/docker11/img41.png" alt="photo 41" /> <img src="/assets/img/posts/docker11/img42.png" alt="photo 42" /> <img src="/assets/img/posts/docker11/img43.png" alt="photo 43" /></li>
  <li>
    <p>synchronise하다 <img src="/assets/img/posts/docker11/img44.png" alt="photo 44" /></p>
  </li>
  <li>10장과 비슷한 오류 나와서 일단 포기</li>
</ul>]]></content><author><name></name></author><category term="Study" /><category term="Docker &amp; Kubernetes" /><category term="KHUDA" /><summary type="html"><![CDATA[CI/CD의 이해 Continuous Integration: 개발자가 코드를 지속적으로 통합하고 테스트하는 프로세스 소프트웨어를 개발하면서 개발자는 코드를 작성한 후에 깃과 같은 버전 관리 시스템에 push하게 되는데 이때 CI 소프트웨어는 새로운 코드를 기존 코드와 통합하고 자동으로 테스트한다 Continuous Deployment: 지속적 전달 도는 지속적 배포라는 뜻 지속적 전달: 코드를 배포할 수 이쓴 환경을 준비하는 과정까지 지속적 배포: 실제로 코드를 배포하는 것까지 → 교재에서 지속적 전달을 의미]]></summary></entry><entry><title type="html">도커와 쿠버네티스 7: 쿠버네티스의 기본 구조</title><link href="https://daniazie.github.io/ms/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A47/" rel="alternate" type="text/html" title="도커와 쿠버네티스 7: 쿠버네티스의 기본 구조" /><published>2024-08-13T00:00:00+09:00</published><updated>2024-08-13T00:00:00+09:00</updated><id>https://daniazie.github.io/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A47</id><content type="html" xml:base="https://daniazie.github.io/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A47/"><![CDATA[<h2 id="구버네티스의-개념">구버네티스의 개념</h2>
<h3 id="구버네티스의-어원과-역사">구버네티스의 어원과 역사</h3>
<ul>
  <li>쿠버네티스: 컨테이너화된 애플리케이션의 자동 배포, 확장 및 관리를 해주는 오픈소스 플랫폼
    <ul>
      <li>Kubernetes: 고대 그리스러로, 배의 조타수를 의미한다</li>
    </ul>
  </li>
  <li>구글에서 시작한 사내 프로젝트로 2014년에 발표되었다
    <ul>
      <li>초기 디자인 대부분은 구글의 Borg 클러스터 매니저의 영향을 많이 받았는데 Borg는 구글 나애에서 사용하는 시스템으로 수천 개의 서버에서 수백만개의 작업을 실행하고 관리하는 시스템이다</li>
      <li>2015년: 쿠버네티스 1.0 버전이 발표되었다</li>
      <li>2016: 쿠버네티스 패키지 관리 프로그램인 Helm이 발표되었다 (9장에서 자세히 다룬다고 함)
        <h2 id="쿠버네티스의-구조">쿠버네티스의 구조</h2>
        <h3 id="쿠버네티스-클러스터">쿠버네티스 클러스터</h3>
      </li>
    </ul>
  </li>
  <li>쿠버네티스는 다수의 노드로 구성되는 경우가 많다
    <ul>
      <li>크게, 마스터 노드와 워커 노드로 구분됨 → 개발자는 주로 마스터 노드와 사용자는 인터넷을 통해 워커 노드와 통신하는 경우 많다</li>
    </ul>
  </li>
  <li>Container Network Interfaces: 쿠버네티스 클러스터에 존재하는 컨테이너 간의 통신을 위해 필요한 인터페이스임
    <ul>
      <li>이를 사용하려면 쿠버네티스 네트워크 플러그인을 제공하는데, 대표적인 플러그인은 Flannel과 calico이다 → 교재가 calico를 사용한다</li>
    </ul>
  </li>
</ul>

<h3 id="컨트롤-플레인">컨트롤 플레인</h3>
<ul>
  <li>Control Plane: 크버네티스 클러스터 전반의 작업을 관리하는 역할을 한다
    <h4 id="api-서버">API 서버</h4>
  </li>
  <li>쿠버네티스의 작업은 kubectl 명령어를 통해 마스터 노드의 kube-apiserver에게 API 요청을 보냄으로써 이루어진다</li>
  <li>쿠버네티스 컨트롤 플레인에서의 프런트엔드 역할을 한다</li>
</ul>

<h4 id="etcd">etcd</h4>
<ul>
  <li>쿠버네티스 클러스터에 존재하는 모든 데이터를 저장하는 key-value 저장소</li>
</ul>

<h4 id="스케줄러">스케줄러</h4>
<ul>
  <li>쿠버네티스에서는 이후 배울 파드(pod)라는 오프젝트를 통해 애플리케이션을 실행한다
    <ul>
      <li>파드: 쿠버네티스 클러스터를 구성하는 노드 중 하나에 실행된다 → 새롭게 생성되는 파드를 어느 노드에 실행시킬지 정하는 역할을 kube-scheduler가 수행한다</li>
    </ul>
  </li>
</ul>

<h4 id="컨트롤러-매니저">컨트롤러 매니저</h4>
<ul>
  <li>쿠버네티스 리소스를 관리하고 제어하는 역할을 한다</li>
  <li>마스터 노드에서 실행되며 클러스터 상태를 모니터링한다</li>
  <li>컨트롤러에는 디플로이먼트 컨트롤러, 시비스 컨트롤러, 레플리카셋 컨트롤러 등의 여러 종료가 있다</li>
  <li>각 컨트롤러는 특정 리소스 타입을 관리한다</li>
</ul>

<h3 id="노드">노드</h3>
<h4 id="kubelet">Kubelet</h4>
<ul>
  <li>파드 내부의 컨테이너 실행을 담당한다</li>
  <li>파드의 상태를 모니토링하고, 파드의 상태에 이상이 있다면 해당 파드를 다시 배포한다</li>
</ul>

<h4 id="kube-proxy">Kube-Proxy</h4>
<ul>
  <li>노드에서 네트워크 역할을 수행한다</li>
  <li>노드에 존재하는 파드들이 쿠버네티스 내부/외부와 네트워크 통신을 가능하게 한다</li>
</ul>

<h4 id="컨테이너-런타임">컨테이너 런타임</h4>
<ul>
  <li>컨테이너의 생명주기를 담당한다 → Kubelet은 컨테이너 런타임과 통신하는데, 이떄 사용하는 것이 컨테이너 런타임 인터페이스임</li>
  <li>쿠버네티스가 사용하는 컨테이너 런타임에는 containerd, CRI-O 등이 있다</li>
</ul>

<h4 id="파드">파드</h4>
<ul>
  <li>컨테이너를 실행하기 위한 오프젝트인데, 각 파드는 한 대 혹은 여러 개의 컨테이너를 담을 수 있다
    <ul>
      <li>파드는 컨테이너를 그룹화한 것이라고 생각하면 됨</li>
    </ul>
  </li>
  <li>쿠버네티스에서 다수의 파드들은 여러 워커 노드에 분산되어 실행되는데, 하나의 파드에 속하는 컨테이너들은 모두 같은 노드에서 실행한다
    <ul>
      <li>서로 다른 파드는 서로 다른 노드에서 실행될 수 있지만, 하나의 파드가 분할되어 여러 노드에 실행되는 일은 없다는 것이다 → 하나의 파드는 하나의 노드에서 실행된다 → 컨테이너</li>
    </ul>
  </li>
</ul>

<h3 id="워크로드">워크로드</h3>
<ul>
  <li>쿠버네티스에서 실행되는 애플리케이션</li>
  <li>워크로드가 하나의 컴포넌트 형태로 실행하든, 다수의 컴포넌트가 함께 실행하든 쿠버네티스는 파드 내부엣 워크로드를 실행하게 된다 → 파드는 실행 중인 컨테이너의 집합을 나타낸다</li>
</ul>

<h4 id="레플리카셋">레플리카셋</h4>
<ul>
  <li>파드의 복제를 관리하며 클라이언트가 요구하는 복제본 개수만큼 파드를 복제하고 모니터링하고 관리한다</li>
</ul>

<h4 id="디플로이먼트">디플로이먼트</h4>
<ul>
  <li>애플리케이션의 배포와 스케일링을 관리하는 역할을 담당한다</li>
</ul>

<h4 id="스테이트풀셋">스테이트풀셋</h4>
<ul>
  <li>파드 사이에서 순서와 고유성이 보장되어야 하는 경우에 사용한다</li>
</ul>

<h4 id="데몬셋">데몬셋</h4>
<ul>
  <li>쿠버네티스를 구성하는 모든 노드가 파드의 복사본을 실행하도록 한다</li>
  <li>쿠버네티스 클러스터에 새로운 노드가 추가되면 파드 역시 추가된다</li>
  <li>데몬셋은 주로 로깅, 모니터링, 스터리지 등과 같은 시스템 수준의 서비르를 실행하는 데 사용된다</li>
</ul>

<h4 id="잡과-크론잡">잡과 크론잡</h4>
<ul>
  <li>작업이 정상적으로 완료되고 종료되는 것을 담당한다</li>
  <li>만약, 파드가 정상적으로 종료되지 않는다면 재실행시킨다</li>
  <li>잡: 작업이 한번 종료되는 것을 담당한다</li>
  <li>크론잡: 동일한 작업이 스케줄에 따라 여러 번 수행하는 것을 담당한다
    <ul>
      <li>리눅스에서 아용하는 크론 탭과 비슷한 역할을 한다</li>
    </ul>
  </li>
</ul>

<h3 id="네트워크">네트워크</h3>
<h4 id="서비스">서비스</h4>
<ul>
  <li>이를 사용하면 파드를 여러 개 묶어서 클러스터 외부로 노출시킬 수 있다</li>
  <li>서비스를 사용하는 방법의 장점은 이미 실행 중인 파드를 외부로 노출시키기 위해 파드 내부를 수정할 필요가 없다는 것이다</li>
  <li>쿠버네티스 서비스를 활용하면 실행 중인 파드 수정 없이도 외부에 오출시켜 클라이언트와 통신할 수 있다</li>
</ul>

<h4 id="인그레스">인그레스</h4>
<ul>
  <li>인그레스를 활용하면 쿠버네티스 내부에 존재하는 서비스를 HTTP/HTTPS 루트를 클러스터 외부로 라우팅하는 역할을 한다</li>
</ul>

<h3 id="스토리지">스토리지</h3>
<ul>
  <li>컨테이너에 이런저런 문제가 생기거나 컨테이너가 삭제되거나 재실행되면 해당 컨테이너 내부에 존재하는 파일을 모두 삭제됨 → 컨테이너 내부에 존재하는 파일들은 수명이 짧다</li>
  <li>하지만, 쿠버네티스 스토리지를 활용하면 파드의 상태와 상관없이 파일을 보관할 수 있다다</li>
</ul>]]></content><author><name></name></author><category term="Study" /><category term="Docker &amp; Kubernetes" /><category term="KHUDA" /><summary type="html"><![CDATA[구버네티스의 개념 구버네티스의 어원과 역사 쿠버네티스: 컨테이너화된 애플리케이션의 자동 배포, 확장 및 관리를 해주는 오픈소스 플랫폼 Kubernetes: 고대 그리스러로, 배의 조타수를 의미한다 구글에서 시작한 사내 프로젝트로 2014년에 발표되었다 초기 디자인 대부분은 구글의 Borg 클러스터 매니저의 영향을 많이 받았는데 Borg는 구글 나애에서 사용하는 시스템으로 수천 개의 서버에서 수백만개의 작업을 실행하고 관리하는 시스템이다 2015년: 쿠버네티스 1.0 버전이 발표되었다 2016: 쿠버네티스 패키지 관리 프로그램인 Helm이 발표되었다 (9장에서 자세히 다룬다고 함) 쿠버네티스의 구조 쿠버네티스 클러스터 쿠버네티스는 다수의 노드로 구성되는 경우가 많다 크게, 마스터 노드와 워커 노드로 구분됨 → 개발자는 주로 마스터 노드와 사용자는 인터넷을 통해 워커 노드와 통신하는 경우 많다 Container Network Interfaces: 쿠버네티스 클러스터에 존재하는 컨테이너 간의 통신을 위해 필요한 인터페이스임 이를 사용하려면 쿠버네티스 네트워크 플러그인을 제공하는데, 대표적인 플러그인은 Flannel과 calico이다 → 교재가 calico를 사용한다]]></summary></entry><entry><title type="html">도커와 쿠버네티스 8: 쿠버네티스 실습 환경 구축</title><link href="https://daniazie.github.io/ms/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A48/" rel="alternate" type="text/html" title="도커와 쿠버네티스 8: 쿠버네티스 실습 환경 구축" /><published>2024-08-13T00:00:00+09:00</published><updated>2024-08-13T00:00:00+09:00</updated><id>https://daniazie.github.io/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A48</id><content type="html" xml:base="https://daniazie.github.io/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A48/"><![CDATA[<h2 id="가상머신-복제">가상머신 복제</h2>
<ul>
  <li>쿠버네티스는 서버가 여러 대일 때 좀 더 효율적으로 운영할 수 있음 → 서버 세 대로 쿠버네티스 클러스터를 구축한 후 실습을 진행한다
    <ul>
      <li>서버 대신에 노드라고 함</li>
    </ul>
  </li>
  <li>노드 3대가 있게 ubuntu-server01를 두번 복제한다 <img src="/assets/img/posts/docker8/img1.png" alt="photo 1" />
    <ul>
      <li>Include all network adapter MAC addresses를 선택하고 Full clone을 선택한다</li>
    </ul>
  </li>
</ul>

<h3 id="호스트-이름-변경">호스트 이름 변경</h3>
<ul>
  <li>두 번째, 세 번째 가상머신의 호스트 이름을 바꿔준다 <img src="/assets/img/posts/docker8/img2.png" alt="photo 2" /></li>
</ul>

<h3 id="ip-주소-변경">IP 주소 변경</h3>
<ul>
  <li><code class="language-plaintext highlighter-rouge">ifconfig</code>을 통해서 server02의 IP 주소 확인 <img src="/assets/img/posts/docker8/img3.png" alt="photo 3" />
    <ul>
      <li>server1과 똑같아서 바꿔야 된다</li>
    </ul>
  </li>
  <li>아래와 같이 server02의 IP 주소를 바꿔준다 
  <img src="/assets/img/posts/docker8/img4.png" alt="photo 4" /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo netplan apply</code> 명령어를 실행해봤을 때 오류가 나와서 몇번까지 수정해봤는데 결국에는 포기해서 챗지피티한테 물어봐서 아래와 같이 받았다 <img src="/assets/img/posts/docker8/img5.png" alt="photo 5" /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo netplan apply</code> 실행하고 IP 주소 확인<img src="/assets/img/posts/docker8/img6.png" alt="photo 6" />
    <h3 id="dns-설정">DNS 설정</h3>
  </li>
  <li>/etc/hosts 파일을 수정한다 <img src="/assets/img/posts/docker8/img7.png" alt="photo 7" /></li>
  <li><code class="language-plaintext highlighter-rouge">ping</code> 명령어를 이용하여 server01로 ping을 보내면 원활하게 작동하는 것 확인 <img src="/assets/img/posts/docker8/img8.png" alt="photo 8" /></li>
  <li><code class="language-plaintext highlighter-rouge">ssh server01</code> 명령어를 이용하여 server01로 접속해봤을 때 잘 되긴 한다 <img src="/assets/img/posts/docker8/img9.png" alt="photo 9" />
    <ul>
      <li>이름 안 바꿔지만…</li>
    </ul>
  </li>
</ul>

<h3 id="ufw-방화벽-설정">UFW 방화벽 설정</h3>
<ul>
  <li>Uncomplicated FireWall: 리눅스 운영체제에서 작동하는 방화벽이다</li>
  <li>ufw 상태 확인
  <img src="/assets/img/posts/docker8/img10.png" alt="photo 10" />
    <ul>
      <li>상태는 inactive이라고 하면 방화벽 설정 과정은 생략해도 된다고 한다</li>
    </ul>
  </li>
</ul>

<h3 id="네트워크-설정">네트워크 설정</h3>
<ul>
  <li>IPv4를 포워딩하여 iptables가 연결된 트래픽을 볼 수 있게 한다 <img src="/assets/img/posts/docker8/img11.png" alt="photo 11" />
    <ul>
      <li><code class="language-plaintext highlighter-rouge">tee</code>: 출력을 두 곳으로 보낼 수 있는데, 한 곳은 <code class="language-plaintext highlighter-rouge">tee</code> 다음에 명시되어 있는 파일로 출력되고 다른 한 곳은 표준 출력(stdout)이다
        <ul>
          <li><code class="language-plaintext highlighter-rouge">tee</code> 명령어를 활용하면 화면에 출력됨과 동시에 파일에 저장된다</li>
        </ul>
      </li>
      <li><code class="language-plaintext highlighter-rouge">overlay</code>: 리눅스 커널의 네트워크 드라이버를 가리킨다
        <ul>
          <li>서로 다른 호스트에 존재하는 파드 간의 네트워크 연결을 가능하게 하는 기술이다 → 여러 개의 독립적인 네트워크 레이어를 겹쳐서 하나로 연결된 네트워크를 생성한다</li>
        </ul>
      </li>
      <li><code class="language-plaintext highlighter-rouge">br_netfilter</code>: 네트워크 패킥 처리 관련 모듈러로써 iptables/netfilter 규칙이 적용되게 한다
        <ul>
          <li>컨테이너와 호스트 간의 인터페이스 등에서 발생하는 트래픽에 대해 규칙을 적용해 트래픽을 관리한다는 의미</li>
        </ul>
      </li>
      <li><code class="language-plaintext highlighter-rouge">EOF</code>: 문서의 마지막이라는 뜻</li>
    </ul>
  </li>
  <li>다음은 아래와 같은 명령어를 입력한다 <img src="/assets/img/posts/docker8/img12.png" alt="photo 12" />
    <ul>
      <li><code class="language-plaintext highlighter-rouge">modprobe</code>: 리눅스 커널 모듈 관리 도구 → 특정 모듈을 로드하거나 제거할 수 있는 도구</li>
    </ul>
  </li>
  <li>그리고 <code class="language-plaintext highlighter-rouge">sysctl</code> 매개변수를 설정한다
  <img src="/assets/img/posts/docker8/img13.png" alt="photo 13" />
    <ul>
      <li><code class="language-plaintext highlighter-rouge">sysctl</code> 매개변수를 설정하면 재부팅 후에도 값이 유지된다</li>
      <li>브릿지 네트워크 인터페이스에 대한 ipv4 트래픽이 iptables 규칙에 의해 처리되도록 만들어준다</li>
      <li>커널 처리하는 패킷에 대해 외부로 ipv4 포워딩이 가능하게 만들어 준다</li>
    </ul>
  </li>
  <li>아래와 같이 입력하고 재부팅하지 않고 <code class="language-plaintext highlighter-rouge">sysctl</code> 매개변수를 적용할 수 있다 <img src="/assets/img/posts/docker8/img14.png" alt="photo 14" /></li>
</ul>

<h3 id="containerd-설정">containerd 설정</h3>
<ul>
  <li>아래 명령어를 입력한다
    <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre>  <span class="nb">sudo mkdir</span> <span class="nt">-p</span> /etc/containerd
  containerd config default | <span class="nb">sudo tee</span> /etc/containerd/config.toml
</pre></td></tr></tbody></table></code></pre></div>    </div>
    <ul>
      <li>두번째 명령어를 입력해봤을 때 잘 안 되더라…</li>
    </ul>
  </li>
  <li>config.toml을 수정한다 <img src="/assets/img/posts/docker8/img15.png" alt="photo 15" /></li>
  <li>containerd 재시작하고 상태 확인 <img src="/assets/img/posts/docker8/img16.png" alt="photo 16" /></li>
</ul>

<h3 id="swap-메모리-비활성화">swap 메모리 비활성화</h3>
<ul>
  <li>쿠버네티스 컨테이너를 원활하게 관리하려면 swap 메모리 영역을 비활성화해야 한다</li>
  <li>swap 메모리가 할장되어 있는지 확인 <img src="/assets/img/posts/docker8/img17.png" alt="photo 17" />
    <ul>
      <li><code class="language-plaintext highlighter-rouge">free -h</code> 명령어를 통해 메모리 공간 확인</li>
    </ul>
  </li>
  <li>swap이 활성화 중인지 확인 <img src="/assets/img/posts/docker8/img18.png" alt="photo 18" />
    <ul>
      <li>존재해서 활성화되어 있대</li>
    </ul>
  </li>
  <li>swap 메모리를 비활성화한다
  <img src="/assets/img/posts/docker8/img19.png" alt="photo 19" /></li>
  <li>비활성화 중인지 다시 확인 <img src="/assets/img/posts/docker8/img20.png" alt="photo 20" /></li>
  <li>fstab 파일을 수정하여 /swap.img를 주석으로 처리한다 <img src="/assets/img/posts/docker8/img21.png" alt="photo 21" /></li>
</ul>

<h2 id="쿠버네티스-설치">쿠버네티스 설치</h2>
<ul>
  <li>쿠버네티스를 설치하기 전에 apt 패키지 목록을 업데이트하고 쿠버네티스에 한다 <img src="/assets/img/posts/docker8/img22.png" alt="photo 22" />
    <ul>
      <li>오류가 나오고 하루종일 고쳐보다보니 ubuntu-server01을 삭제하고 ubuntu-server02을 복제해봐야 겠다 <img src="/assets/img/posts/docker8/img23.png" alt="photo 23" />
        <ul>
          <li>성공쓰</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>signing 키 다운로드를 위해서는 필요한 디렉터리를 생성한 후 쿠버네티스 apt 리포지토리를 추가한다 <img src="/assets/img/posts/docker8/img24.png" alt="photo 24" /></li>
  <li>구글 클라우드의 공개 signing 키를 다운로드한다 <img src="/assets/img/posts/docker8/img25.png" alt="photo 25" /></li>
  <li>패키지를 업데이트해야 되는데 아래와 같은 오류가 나와서 이를 해결해야 겠다 <img src="/assets/img/posts/docker8/img26.png" alt="photo 26" />
    <ul>
      <li>지피티 쌤한테 물어보니까 kubernetes-xenial이 ubuntu 24랑 안 맞아서 대신에 kubernetes-jammy를 설치해야 되네 <img src="/assets/img/posts/docker8/img27.png" alt="photo 27" />
        <ul>
          <li>아직 안 된다. Kubernetes 사이트를 보니까 <img src="/assets/img/posts/docker8/img28.png" alt="photo 28" /></li>
          <li>Kubernetes 홈페이지를 참고해서 <img src="/assets/img/posts/docker8/img29.png" alt="photo 29" />
            <ul>
              <li>성공쓰</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li>kubelet, kubeadm과 kubectl을 설치한다 <img src="/assets/img/posts/docker8/img30.png" alt="photo 30" /></li>
  <li>아래와 명령어를 입력한다 <img src="/assets/img/posts/docker8/img31.png" alt="photo 31" /></li>
  <li>버전 확인 <img src="/assets/img/posts/docker8/img32.png" alt="photo 32" /></li>
</ul>

<h3 id="마스터-노드-설정">마스터 노드 설정</h3>
<ul>
  <li>server01은 마스터 노드가 되고 server02은 워커노드가 되게 만든다</li>
  <li>쿠버네티스 인증서 상태 확인 <img src="/assets/img/posts/docker8/img33.png" alt="photo 33" /></li>
  <li>kubeadm이 사용할 수 있는 이미지 리스트 확인 <img src="/assets/img/posts/docker8/img34.png" alt="photo 34" /></li>
  <li>이미지를 pull하겠다 <img src="/assets/img/posts/docker8/img35.png" alt="photo 35" /></li>
  <li><code class="language-plaintext highlighter-rouge">kubeadm</code>을 사용해 초기화한다 <img src="/assets/img/posts/docker8/img36.png" alt="photo 36" />
    <ul>
      <li><code class="language-plaintext highlighter-rouge">--apiserver-advertise-address</code>: 쿠버네티스 마스터 노드의 IP 주소를 입력한다</li>
      <li><code class="language-plaintext highlighter-rouge">--pod-network-cidr</code>: 네트워크 대역을 설정할 수 있다</li>
      <li>calico를 사용해서 192.168.0.0/16을 입력한다</li>
      <li>워커 노드와 마스터 노드를 연결하는 구문을 받는데 Notepad에 저장했다</li>
    </ul>
  </li>
  <li>인증서 상태 다시 확인 <img src="/assets/img/posts/docker8/img37.png" alt="photo 37" /></li>
  <li>사용자가 쿠버네티스를 활용할 수 있도록 쿠버네티스 설정을 저장할 새로운 디렉터리를 만든 후 기존 설정 파일을 새로운 디렉터리로 복사하고 설정 디렉터리의 소유자와 그룹을 변경해 현재 사용자가 사용할 수 있도록 변경한다 <img src="/assets/img/posts/docker8/img38.png" alt="photo 38" /></li>
  <li>calico로 네트워크를 설정해본다. 먼저 calico를 설치하기 위해 해당 URL에 존재하는 yaml 파일을 실행한다 <img src="/assets/img/posts/docker8/img39.png" alt="photo 39" /></li>
  <li>필요한 커스텀 리소스를 설치한다 <img src="/assets/img/posts/docker8/img40.png" alt="photo 40" /></li>
  <li>다운로드한 파일을 확인하고 이 파일을 활용하여 calico를 설치한다 <img src="/assets/img/posts/docker8/img41.png" alt="photo 41" /></li>
  <li>calico에 대한 파드가 실행 중인지 확인 <img src="/assets/img/posts/docker8/img42.png" alt="photo 42" /></li>
  <li>구성되어 있는 노드 확인 <img src="/assets/img/posts/docker8/img43.png" alt="photo 43" /></li>
</ul>

<h3 id="워커-노드-설정">워커 노드 설정</h3>
<ul>
  <li>server01에 있는 .kube/config을 server02로 복사한다 <img src="/assets/img/posts/docker8/img44.png" alt="photo 44" /></li>
  <li>앞서 저장했던 구문을 활용하여 클러스에 노드를 추가한다 <img src="/assets/img/posts/docker8/img45.png" alt="photo 45" /></li>
  <li>노드 확인 <img src="/assets/img/posts/docker8/img46.png" alt="photo 46" /></li>
  <li>server03도 추가하고 노드 확인 <img src="/assets/img/posts/docker8/img47.png" alt="photo 47" /></li>
</ul>

<h3 id="쿠버네티스로-실행하는-hello-world">쿠버네티스로 실행하는 Hello World!</h3>
<ul>
  <li>아래와 같이 입력한다<img src="/assets/img/posts/docker8/img48.png" alt="photo 48" /></li>
</ul>

<h3 id="쿠버네티스-삭제-방법">쿠버네티스 삭제 방법</h3>
<ul>
  <li>쿠버네티스를 삭제하는 방법이 아래와 같다 (실제로 안 했음)
    <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>  <span class="nb">sudo </span>apt-get purge kubeadm kubectl kubelet
  <span class="nb">sudo </span>apt-get remove
  <span class="nb">sudo rm</span> <span class="nt">-rf</span> ~/.kube
</pre></td></tr></tbody></table></code></pre></div>    </div>
    <h2 id="side-note">side note</h2>
  </li>
  <li>실습하다가 server01에서 server02나 server03로 잘 접속하지 않았는데 /etc/netplan에서 존재한 yaml 파일이 있어서 그거를 먼저 삭제하면 잘 되었고 puTTY에서도 잘 접속한다</li>
</ul>]]></content><author><name></name></author><category term="Study" /><category term="Docker &amp; Kubernetes" /><category term="KHUDA" /><summary type="html"><![CDATA[가상머신 복제 쿠버네티스는 서버가 여러 대일 때 좀 더 효율적으로 운영할 수 있음 → 서버 세 대로 쿠버네티스 클러스터를 구축한 후 실습을 진행한다 서버 대신에 노드라고 함 노드 3대가 있게 ubuntu-server01를 두번 복제한다 Include all network adapter MAC addresses를 선택하고 Full clone을 선택한다]]></summary></entry><entry><title type="html">도커와 쿠버네티스 5: 도커를 활용한 django 실습</title><link href="https://daniazie.github.io/ms/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A45/" rel="alternate" type="text/html" title="도커와 쿠버네티스 5: 도커를 활용한 django 실습" /><published>2024-08-06T00:00:00+09:00</published><updated>2024-08-06T00:00:00+09:00</updated><id>https://daniazie.github.io/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A45</id><content type="html" xml:base="https://daniazie.github.io/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A45/"><![CDATA[<h2 id="추가-실습-환경-구촉">추가 실습 환경 구촉</h2>
<h3 id="pyenv-설치">pyenv 설치</h3>
<p>django를 활용하기 위해 pyenv를 설치해야 되는데 이는 파이썬 가상 환경을 관리할 수 있게 해주는 소프트웨어이다</p>
<ul>
  <li>먼저 아래와 같은 프로그램을 설치해야 된다 <img src="/assets/img/posts/docker5/img1.png" alt="photo 1" /></li>
  <li>다음은 아래와 같이 pyenv를 설치할 수 있다 <img src="/assets/img/posts/docker5/img2.png" alt="photo 2" /></li>
  <li>홈 디렉터리에서 아래 명령어를 입력하여 .bashrc 파일이 있는지 확인한다 <img src="/assets/img/posts/docker5/img3.png" alt="photo 3" />
    <ul>
      <li>오호 있다</li>
    </ul>
  </li>
  <li><code class="language-plaintext highlighter-rouge">vim .bashrc</code> 명령어를 입력하여 .bashrc 파일을 아래와 같이 수정한다 <img src="/assets/img/posts/docker5/img4.png" alt="photo 4" /></li>
  <li>
    <p>아래 명령어를 이용하여 셸을 재시작</p>

    <p><img src="/assets/img/posts/docker5/img5.png" alt="photo 5" /></p>
  </li>
  <li>터미널에서 <code class="language-plaintext highlighter-rouge">pyenv</code>를 입력하면 pyenv가 성공적으로 설치되었는지 확인할 수 있다 <img src="/assets/img/posts/docker5/img6.png" alt="photo 6" /></li>
</ul>

<h3 id="pyenv를-활용한-파이썬-가상-환경-구축">pyenv를 활용한 파이썬 가상 환경 구축</h3>
<ul>
  <li>아래와 같은 명령어를 입력하면 설치 가능한 파이썬 버전을 확인한다. <img src="/assets/img/posts/docker5/img7.png" alt="photo 7" /></li>
  <li>교재와 같이  3.11.6 버전을 설치하겠다 <img src="/assets/img/posts/docker5/img8.png" alt="photo 8" /></li>
  <li>3.11.6 버전을 잘 설치되었는지 확인 <img src="/assets/img/posts/docker5/img9.png" alt="photo 9" /></li>
  <li><code class="language-plaintext highlighter-rouge">pyenv virtualenv</code> 명령어를 활용하여 py3_11_6이라는 가상 환경을 만들고 목록 확인 <img src="/assets/img/posts/docker5/img10.png" alt="photo 10" /></li>
  <li>아래와 같이 가상 환경을 실행한다 <img src="/assets/img/posts/docker5/img11.png" alt="photo 11" /></li>
  <li>아래 명령어를 입력하여 필요한 라이브러리를 설치한다
    <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre>pip <span class="nb">install </span>django
pip <span class="nb">install </span>gunicorn
pip <span class="nb">install </span>psycopg2-binary
</pre></td></tr></tbody></table></code></pre></div>    </div>
    <ul>
      <li>django: 웹 프레임워크</li>
      <li>gunicorn: 웹 서버와 통신하기 위한 라이브러리</li>
      <li>PostgreSQL을 활용하기 위해 사용하는 라이브러리</li>
    </ul>
  </li>
  <li>아래와 같이 각자 라이브러리의 버전 확인 <img src="/assets/img/posts/docker5/img12.png" alt="photo 12" /></li>
</ul>

<h3 id="tree-설치">tree 설치</h3>
<ul>
  <li>리눅스 시스템에서 파일 시스템 구조를 시각적으로 쉽게 확인할 수 있는 tree를 설치한다 <img src="/assets/img/posts/docker5/img13.png" alt="photo 13" /></li>
  <li>설치 후에 <code class="language-plaintext highlighter-rouge">tree [경로]</code>를 입력하면 해당 경로를 포함한 하위 디렉터리 및 파일 구조를 확인할 수 있다
  <img src="/assets/img/posts/docker5/img14.png" alt="photo 14" /></li>
</ul>

<h3 id="django를-실행하기-위한-네트워크-설정">django를 실행하기 위한 네트워크 설정</h3>
<ul>
  <li>Tools의 Properties에 들어가고, 여기서 NAT Networks 선택하고 아래와 같이 포트포워딩을 설정한다 <img src="/assets/img/posts/docker5/img15.png" alt="photo 15" />
    <ul>
      <li>호스트 포트의 8000변과 ubuntu-server01의 IP인 10.0.2.4의 8000번 포트를 연결하고, 호스트 포트의 80번 포트를 ubuntu-server01의 80번 포트를 연결시킨다</li>
      <li>이 과정을 통해서 호스트에서 가상 머신으로 접속이 가능하다</li>
    </ul>
  </li>
</ul>

<h2 id="yaml-기초">YAML 기초</h2>
<h3 id="yaml의-개념">YAML의 개념</h3>
<ul>
  <li>YAML Ain’t Markup Language의 졸임말인데 도커 컴포즈를 사용할 때 YAML 파일을 활용며, 쿠버네티스에서도 YAML 파일을 사용한다
    <h3 id="pyyaml-설치">pyyaml 설치</h3>
  </li>
  <li>먼저 pyyaml 라이브러리를 설치한다 <img src="/assets/img/posts/docker5/img16.png" alt="photo 16" /></li>
  <li>yaml 라이브러리를 잘 설치되었는지 확인 <img src="/assets/img/posts/docker5/img17.png" alt="photo 17" /></li>
</ul>

<h3 id="yaml-문법">YAML 문법</h3>
<ul>
  <li>먼저 실습 디렉터리를 생성하겠다 <img src="/assets/img/posts/docker5/img18.png" alt="photo 18" /></li>
  <li><code class="language-plaintext highlighter-rouge">vim</code> 명령어를 사용해서 yaml_practice.yml 파일을 생성하여 수정한다 <img src="/assets/img/posts/docker5/img19.png" alt="photo 19" />
    <ul>
      <li>YAML 파일은 기본적으로 <code class="language-plaintext highlighter-rouge">{key:value}</code> 구조를 사용하는 파이썬의 딕셔너리 자료형과 비슷한다</li>
    </ul>
  </li>
  <li>아래와 같이 생성한 YAML 파일을 분석한다 <img src="/assets/img/posts/docker5/img20.png" alt="photo 20" /></li>
  <li><code class="language-plaintext highlighter-rouge">{'name':'nginx', 'image': 'nginx:latest'}</code>와 같이 name과 image에 대한 데이터가 같은 딕셔너리로 구성되는데, 이를 가능하게 하는 것이 yaml 파일에서의 ‘-‘이다
    <ul>
      <li>’-‘로 시작하는 줄은 한 요소의 시작헤 해당하면 ‘-‘로 시작하지 않는 줄은 ‘-‘로 시작하는 줄의 다음 요소호 추가된다</li>
    </ul>
  </li>
</ul>

<h2 id="도커를-활용한-django-실행">도커를 활용한 django 실행</h2>
<h3 id="도커-호스트에-django-프로젝트-생성">도커 호스트에 django 프로젝트 생성</h3>
<ul>
  <li>ch05 폴더에서 ex02라는 디렉터리를 생성하여 들어간다 <img src="/assets/img/posts/docker5/img21.png" alt="photo 21" /></li>
  <li>새로운 django 프로젝트를 생성하고 파일 목록 확인 <img src="/assets/img/posts/docker5/img22.png" alt="photo 22" /></li>
  <li><code class="language-plaintext highlighter-rouge">vim settings.py</code>를 입력하고 settings.py를 아래와 같이 수정한다 <img src="/assets/img/posts/docker5/img23.png" alt="photo 23" /></li>
  <li>django 프로젝트를 실행하기 전에 데이터베이스 변경사항을 적용한다 <img src="/assets/img/posts/docker5/img24.png" alt="photo 24" /></li>
  <li><code class="language-plaintext highlighter-rouge">runserver</code> 명령어를 이용하여 django 프로젝트 실행 <img src="/assets/img/posts/docker5/img25.png" alt="photo 25" />
    <ul>
      <li>0.0.0.0:8000: 8000번 포트를 활용하겠다는 뜻</li>
    </ul>
  </li>
  <li>웹 브라우저 주소창에 127.0.0.1:8000을 입력하면 접속이 잘 되는 것 확인 <img src="/assets/img/posts/docker5/img26.png" alt="photo 26" /></li>
</ul>

<h3 id="django-이미지-빌드">django 이미지 빌드</h3>
<ul>
  <li>django 이미지 빌드 과정
    <ul>
      <li>디렉터리 정리 → requirements.txt 파일 작성 → Dockerfile 파일 작성 → 이미지 빌드
        <h4 id="디렉터리-정리">디렉터리 정리</h4>
      </li>
    </ul>
  </li>
  <li>ch05 폴더에서 ex02를 ex03라는 폴더로 복사고 파일 목록을 확인한다 <img src="/assets/img/posts/docker5/img27.png" alt="photo 27" /></li>
</ul>

<h4 id="requirementstxt-파일-작성">requirements.txt 파일 작성</h4>
<ul>
  <li>requirements.txt 파일을 만들고 django 버전을 추가한다 <img src="/assets/img/posts/docker5/img28.png" alt="photo 28" /></li>
</ul>

<h4 id="dockerfile-파일-작성">Dockerfile 파일 작성</h4>
<ul>
  <li>도커 이미지 파일을 생성하기 위해 필요한 명령어를 모아 놓은 파일을 Dockerfile이라고 함</li>
  <li><code class="language-plaintext highlighter-rouge">vim Dockerfile</code> 명령어를 이용해서 Dockerfile을 생성하는데 아래와 같이 작성한다 <img src="/assets/img/posts/docker5/img29.png" alt="photo 29" />
    <ul>
      <li><code class="language-plaintext highlighter-rouge">FROM</code>: 베이스 이미지</li>
      <li><code class="language-plaintext highlighter-rouge">WORKDIR</code>: 리눅스의 cd 명령어롸 비슷하다</li>
      <li><code class="language-plaintext highlighter-rouge">COPY</code> 호스트에 존재하는 파일을 도커 이미지의 파일 시스템 경로로 복사하는 명령어</li>
      <li><code class="language-plaintext highlighter-rouge">RUN</code>: 이미지 빌드 시 실행하고 싶은 명령어를 실행</li>
      <li><code class="language-plaintext highlighter-rouge">CMD</code>: 서비스(컨테이너)를 실행</li>
      <li><code class="language-plaintext highlighter-rouge">EXPOSE</code>: 8000번 포트를 연다</li>
    </ul>
  </li>
  <li>ex03 파일 목록 확인 <img src="/assets/img/posts/docker5/img30.png" alt="photo 30" /></li>
</ul>

<h4 id="이미지-빌드">이미지 빌드</h4>
<ul>
  <li>도커 클라이언트에서 아래와 같은 명령어를 도커 데몬에 전달하면 django 이미지를 생성한다 <img src="/assets/img/posts/docker5/img31.png" alt="photo 31" /></li>
  <li>이미지 생성되었는지 확인 <img src="/assets/img/posts/docker5/img32.png" alt="photo 32" /></li>
</ul>

<h3 id="django-컨테이너-실행">django 컨테이너 실행</h3>
<ul>
  <li><code class="language-plaintext highlighter-rouge">-d</code> 옵션을 이용하여 컨테이너를 백그라운드로 실행하고 <code class="language-plaintext highlighter-rouge">-p &lt;도커 호스트 포트&gt;:&lt;컨테이너 포트&gt;</code> 옵션은 포트토워딩 옵션이다  <img src="/assets/img/posts/docker5/img33.png" alt="photo 33" /></li>
  <li>django가 잘 실행되는지 확인 <img src="/assets/img/posts/docker5/img34.png" alt="photo 34" /></li>
</ul>

<h2 id="nginx-django-연동-후-실행">Nginx, django 연동 후 실행</h2>
<h3 id="nginx-컨테이너-실행">Nginx 컨테이너 실행</h3>
<h4 id="디렉터리-정리-1">디렉터리 정리</h4>
<ul>
  <li>ch05 폴더에서 ex04라는 폴더를 생성하고 들어간다 <img src="/assets/img/posts/docker5/img35.png" alt="photo 35" /></li>
  <li>
    <p>아래와 같은 Dockerfile을 생성하고 작성한다</p>

    <p><img src="/assets/img/posts/docker5/img36.png" alt="photo 36" /></p>
  </li>
</ul>

<h4 id="이미지-빌드-1">이미지 빌드</h4>
<ul>
  <li>이전 실습과 비슷하게 <code class="language-plaintext highlighter-rouge">docker image build</code> 명령어를 이용하여 이미지를 빌드하겠다 <img src="/assets/img/posts/docker5/img37.png" alt="photo 37" /></li>
  <li>도커 이미지 목록 확인 <img src="/assets/img/posts/docker5/img38.png" alt="photo 38" /></li>
</ul>

<h4 id="컨테이너-실행">컨테이너 실행</h4>
<ul>
  <li>도커 컨테이너를 실행하고 실행중인 컨테이너 목록 확인 <img src="/assets/img/posts/docker5/img39.png" alt="photo 39" /></li>
  <li>Nginx가 잘 실행되는지 확인 <img src="/assets/img/posts/docker5/img40.png" alt="photo 40" /></li>
  <li>Nginx 내부 설정 파일 확인 <img src="/assets/img/posts/docker5/img41.png" alt="photo 41" /></li>
</ul>

<h3 id="gunicorn을-통한-연동">gunicorn을 통한 연동</h3>
<ul>
  <li>django와 Nginx를 연동하기 위해서는 중간에는 gunicorn이 필요한다 → Nginx와 django를 연결해주는 역할을 수행한다고 생각하면 됨</li>
</ul>

<h3 id="django-이미지-빌드-1">django 이미지 빌드</h3>
<h4 id="디렉터리-정리-2">디렉터리 정리</h4>
<ul>
  <li>디렉터리를 아래와 같이 정리한다 <img src="/assets/img/posts/docker5/img42.png" alt="photo 42" /></li>
  <li>ex05 디렉터리에 들어가고 requirements.txt를 아래와 같이 수정한다 <img src="/assets/img/posts/docker5/img43.png" alt="photo 43" /></li>
  <li>그리고 Dockerfile도 아래와 같이 수정한다 <img src="/assets/img/posts/docker5/img44.png" alt="photo 44" /></li>
</ul>

<h4 id="django-이미지-빌드-2">django 이미지 빌드</h4>
<ul>
  <li>아래와 같이 이미지 빌드한다 <img src="/assets/img/posts/docker5/img45.png" alt="photo 45" /></li>
  <li>이미지 목록 확인 <img src="/assets/img/posts/docker5/img46.png" alt="photo 46" /></li>
</ul>

<h3 id="nginx-이미지-빌드">Nginx 이미지 빌드</h3>
<h4 id="nginx-디렉터리-정리">Nginx 디렉터리 정리</h4>
<ul>
  <li>아까 생성한 MyNginx02 폴더에 들어간다 <img src="/assets/img/posts/docker5/img47.png" alt="photo 47" /></li>
  <li>MyNginx02에서 default.conf라는 파일을 생성하고 아래와 같이 작성한다 <img src="/assets/img/posts/docker5/img48.png" alt="photo 48" />
    <ul>
      <li>djangotest: django를 이용해 생성하게 될 컨테이너 이름이다
        <ul>
          <li>Nginx는 80번 포트로 받은 요청을 djangotest 컨테이너의 8000번 포트로 전송하겠다는 뜻</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Dockerfile를 아래와 같이 수정한다 <img src="/assets/img/posts/docker5/img49.png" alt="photo 49" /></li>
</ul>

<h4 id="nginx-이미지-빌드-1">Nginx 이미지 빌드</h4>
<ul>
  <li>이전 마찬가지로 <code class="language-plaintext highlighter-rouge">docker image build</code> 명령어를 통해서 Nginx 이미지를 빌드하겠다 <img src="/assets/img/posts/docker5/img50.png" alt="photo 50" /></li>
</ul>

<h3 id="django와-nginx-연동-후-컨테이너-실행">django와 Nginx 연동 후 컨테이너 실행</h3>
<h4 id="컨테이너-실행-1">컨테이너 실행</h4>
<ul>
  <li>
    <p>먼저 도커 네트워크를 생성해야 된다고 한다 <img src="/assets/img/posts/docker5/img51.png" alt="photo 51" /></p>
  </li>
  <li>
    <p>호스트의 웹 브라우저에서 주소창에 127.0.0.1:80을 입력하면 포트포워딩 기능을 통해 10.0.2.4:80으로 트래픽이 전달됨 → nginxtest 컨테이너를 통과한 후 djangotest 컨테이너에 접속하게 되어 django 서비스를 활용할 수 있게 됨</p>
  </li>
  <li>mynetwork02를 활용한 djangotest 컨테이너를 생성하여 실행해보겠다 <img src="/assets/img/posts/docker5/img52.png" alt="photo 52" /></li>
  <li>마찬가지로 nginxtest 컨테이너를 실행해보겠다 <img src="/assets/img/posts/docker5/img53.png" alt="photo 53" /></li>
  <li>127.0.0.1:80로 들어가보면 아래와 같이 나타나게 된다 <img src="/assets/img/posts/docker5/img54.png" alt="photo 54" /></li>
</ul>

<h2 id="nginx-django-posgresql-컨테이너-연동">Nginx, django, PosgreSQL 컨테이너 연동</h2>
<h3 id="postgresql-컨테이너-실행">PostgreSQL 컨테이너 실행</h3>
<h4 id="디렉터리-정리-3">디렉터리 정리</h4>
<ul>
  <li>ex06라는 폴더를 생성하고 들어간다 <img src="/assets/img/posts/docker5/img55.png" alt="photo 55" /></li>
</ul>

<h4 id="dockerfile-작성">Dockerfile 작성</h4>
<ul>
  <li>Dockerfile를 아래와 같이 작성한다
  <img src="/assets/img/posts/docker5/img56.png" alt="photo 56" /></li>
</ul>

<h4 id="이미지-빌드-2">이미지 빌드</h4>
<ul>
  <li>아래와 같아 이미지를 빌드한다 <img src="/assets/img/posts/docker5/img57.png" alt="photo 57" /></li>
</ul>

<h4 id="컨테이너-실행-2">컨테이너 실행</h4>
<ul>
  <li>먼저 도커 볼륨을 생성해야 된다 <img src="/assets/img/posts/docker5/img58.png" alt="photo 58" /></li>
  <li>다음은 아래와 같이 컨테이너를 실행해보겠다 <img src="/assets/img/posts/docker5/img59.png" alt="photo 59" />
    <ul>
      <li><code class="language-plaintext highlighter-rouge">-e</code> 옵션을 이용하여 환경변수를 수정한다</li>
    </ul>
  </li>
</ul>

<h3 id="django-nginx-postgresql-연동">django, Nginx, PostgreSQL 연동</h3>
<h4 id="디렉터리-정리-4">디렉터리 정리</h4>
<ul>
  <li>아래와 같이 정리한다 <img src="/assets/img/posts/docker5/img60.png" alt="photo 60" /></li>
</ul>

<h3 id="django-이미지-빌드-3">django 이미지 빌드</h3>
<ul>
  <li>myapp 폴더에 있는 myapp폴더에 들어가고 settings.py를 아래와 같이 수정한다 <img src="/assets/img/posts/docker5/img61.png" alt="photo 61" /></li>
  <li>
    <p>그리고 myDjango03에 있는 requirements.txt를 아래와 같이 수정한다 <img src="/assets/img/posts/docker5/img62.png" alt="photo 62" /></p>
  </li>
  <li>Dockerfile에 추가할 내용을 없어서 따로 수정하지 않았다</li>
  <li>아래와 같이 빌드한다 <img src="/assets/img/posts/docker5/img63.png" alt="photo 63" /></li>
</ul>

<h3 id="nginx-이미지-빌드-2">Nginx 이미지 빌드</h3>
<ul>
  <li>수정 없이 빌드 <img src="/assets/img/posts/docker5/img64.png" alt="photo 64" /></li>
</ul>

<h3 id="django-nginx-postgresql-연동-후-컨테이너-실행">django, Nginx, PostgreSQL 연동 후 컨테이너 실행</h3>
<p>호스트에서 웹 브라우저를 실행한 후 127.0.0.1:80에 접속하면 포트포워딩을 통해 10.0.2.4:80으로 트래픽이 전달됨 → nginxtest 컨테이너를 거쳐 djangotest 컨테이너에 접속할 수 있으며, djangotest 컨테이너는 postgrestest 컨테이너를 통해 데이터베이스를 활용하게 됨</p>

<ul>
  <li>먼저 네트워크를 생성해야 된다 <img src="/assets/img/posts/docker5/img65.png" alt="photo 65" /></li>
  <li>PostgreSQL 컨테이너를 실행한다 <img src="/assets/img/posts/docker5/img66.png" alt="photo 66" /></li>
  <li>이전 실습에 생성한 djangotest와 nginxtest 컨테이너를 삭제하고 새로운 걸로 실행한다 <img src="/assets/img/posts/docker5/img67.png" alt="photo 67" /></li>
  <li>nginxtest 컨테이너 실행 <img src="/assets/img/posts/docker5/img68.png" alt="photo 68" /></li>
  <li>
    <p>django가 잘 실행하는 걸 확인 <img src="/assets/img/posts/docker5/img69.png" alt="photo 69" /></p>
  </li>
  <li>djangotest 컨테이너 내부에 들어가 django와 PostgreSQL이 연결되었는지 확인 <img src="/assets/img/posts/docker5/img70.png" alt="photo 70" /></li>
</ul>

<h2 id="nginx-django와-로컬-postgresql-연동">Nginx, django와 로컬 PostgreSQL 연동</h2>
<h3 id="postgresql-로컬-설치">PostgreSQL 로컬 설치</h3>
<ul>
  <li>리포지토리 설정 파일을 생성한다 <img src="/assets/img/posts/docker5/img71.png" alt="photo 71" /></li>
  <li>리포지토리 인증키를 불러온다 <img src="/assets/img/posts/docker5/img72.png" alt="photo 72" /></li>
  <li>우분투 패키지 리스트를 업데이트한다 <img src="/assets/img/posts/docker5/img73.png" alt="photo 73" /></li>
  <li>최종적으로 PostgreSQL을 설치한다 <img src="/assets/img/posts/docker5/img74.png" alt="photo 74" /></li>
  <li>PostgreSQL이 실행 중인지 확인 <img src="/assets/img/posts/docker5/img75.png" alt="photo 75" /></li>
  <li>PostgreSQL에 postgres 사용자로 접속한다 <img src="/assets/img/posts/docker5/img76.png" alt="photo 76" /></li>
  <li>데이터베이스 목록 확인 <img src="/assets/img/posts/docker5/img77.png" alt="photo 77" /></li>
  <li>비밀번호를 설정한다 
  <img src="/assets/img/posts/docker5/img78.png" alt="photo 78" /></li>
  <li>/etc/postgresql/16/main에 있는 pg_hba.conf 파일을 아래와 같이 수정한다 <img src="/assets/img/posts/docker5/img79.png" alt="photo 79" /></li>
  <li>postgresql.conf를 아래와 같이 수정한다 <img src="/assets/img/posts/docker5/img80.png" alt="photo 80" /></li>
  <li>PostgreSQL을 재시작하고 상태를 확인한다 <img src="/assets/img/posts/docker5/img81.png" alt="photo 81" /></li>
</ul>

<h3 id="django-이미지-빌드-4">django 이미지 빌드</h3>
<ul>
  <li>디렉터리를 아래와 같이 정리한다 <img src="/assets/img/posts/docker5/img82.png" alt="photo 82" /></li>
  <li>django와 Nginx는 컨테이너 형태로 실행되는 반면 PostgreSQL은 호스트 (가상머신의 로컬_에 설치되어 있기 때문에 <code class="language-plaintext highlighter-rouge">ifconfig</code> 명령어를 이용하여 docker0의 IP주소를 확인한다 → django와 PostgreSQL이 서로 통신하려면 docker0을 이용해야 한다<img src="/assets/img/posts/docker5/img83.png" alt="photo 83" /></li>
  <li>myapp/myapp에 들어가 settings.py를 아래와 같이 수정한다 <img src="/assets/img/posts/docker5/img84.png" alt="photo 84" /></li>
  <li>requirements.txt와 Dockerfile를 수정할 필요가 없어서 바로 이미지를 빌드한다<img src="/assets/img/posts/docker5/img85.png" alt="photo 85" /></li>
</ul>

<h3 id="nginx-이미지-빌드-3">Nginx 이미지 빌드</h3>
<ul>
  <li>default.conf와 Dockerfile을 수정할 필요가 없어서 그대로 빌드한다 <img src="/assets/img/posts/docker5/img86.png" alt="photo 86" /></li>
</ul>

<h3 id="django-nginx-postgresql-연동-1">django, Nginx, PostgreSQL 연동</h3>
<ul>
  <li>컨테이너를 실행 후 연동한다</li>
  <li>먼저 네트워크를 생성한다 <img src="/assets/img/posts/docker5/img87.png" alt="photo 87" /></li>
  <li>djangotest와 nginxtest 컨테이너를 실행한다 <img src="/assets/img/posts/docker5/img88.png" alt="photo 88" /></li>
  <li>django가 잘 실행하고 있는지 확인 <img src="/assets/img/posts/docker5/img89.png" alt="photo 89" /></li>
  <li>djangotest 내부에 들어가고 데이터베이스 연결 상태를 확인한다 <img src="/assets/img/posts/docker5/img90.png" alt="photo 90" /></li>
</ul>

<h2 id="도커-컴포즈를-활용한-컨테이너-실행">도커 컴포즈를 활용한 컨테이너 실행</h2>
<h3 id="도커-컴포즈의-개념">도커 컴포즈의 개념</h3>
<ul>
  <li>도커 컴포즈: 도커를 활용하여 다수의 컨테이너 형태의 애플리케이션을 실행할 수 있는 도구</li>
  <li>실행하고자 하는 애플리케이션의 설정 내용들을 YAML 파일로 작성하는 방법으로 고커 컴포즈를 활용할 수 있다</li>
</ul>

<h3 id="도커-컴포즈-설치">도커 컴포즈 설치</h3>
<ul>
  <li>먼저 pip3를 설치한다 <img src="/assets/img/posts/docker5/img91.png" alt="photo 91" /></li>
  <li>그리고 도커 컴포즈를 설치한다 <img src="/assets/img/posts/docker5/img92.png" alt="photo 92" />
    <ul>
      <li>오류가 나오긴 하지만 도커 컴포즈가 있다고 해서 괜찮을 듯…?</li>
    </ul>
  </li>
</ul>

<h3 id="실습-디렉터리-구성">실습 디렉터리 구성</h3>
<ul>
  <li>아래와 같이 디렉터리를 구성한다 <img src="/assets/img/posts/docker5/img93.png" alt="photo 93" /></li>
</ul>

<h3 id="docker-composeyml-파일-작성">docker-compose.yml 파일 작성</h3>
<ul>
  <li>docker-compose.yml을 생성하고 아래와 같이 작성한다 <img src="/assets/img/posts/docker5/img94.png" alt="photo 94" />
    <ul>
      <li><code class="language-plaintext highlighter-rouge">restart: always</code>: 컨테이너가 정지되면 재실행하라는 명령어</li>
    </ul>
  </li>
</ul>

<h3 id="빌드-및-실행">빌드 및 실행</h3>
<ul>
  <li>아래와 같이 컨테이너를 실행한다 <img src="/assets/img/posts/docker5/img95.png" alt="photo 95" /></li>
  <li>성공쓰 <img src="/assets/img/posts/docker5/img96.png" alt="photo 96" /></li>
  <li>django 컨테이너 내부에 들어가 데이터베이스 연결 상태 확인 <img src="/assets/img/posts/docker5/img97.png" alt="photo 97" /></li>
</ul>

<h3 id="추가-실습">추가 실습</h3>
<ul>
  <li>django, Nginx 컨테이너가 로컬 PostgreSQL과 연결하는 실습을 도커 컴포즈로 진행해본다</li>
  <li>먼저 디렉터리를 아래와 같이 정리한다 <img src="/assets/img/posts/docker5/img98.png" alt="photo 98" /></li>
  <li>docker-compose.yml 파일을 아래와 같이 작성한다 <img src="/assets/img/posts/docker5/img99.png" alt="photo 99" /></li>
  <li>아래와 같이 빌드한다 <img src="/assets/img/posts/docker5/img100.png" alt="photo 100" /></li>
  <li>컨테이너가 실행 중인지 확인 <img src="/assets/img/posts/docker5/img101.png" alt="photo 101" /></li>
  <li>PostgreSQL과 연동되었는지 확인 <img src="/assets/img/posts/docker5/img102.png" alt="photo 102" /></li>
  <li>컨테이너를 정지시킨다 <img src="/assets/img/posts/docker5/img103.png" alt="photo 103" /></li>
</ul>]]></content><author><name></name></author><category term="Study" /><category term="Docker &amp; Kubernetes" /><category term="KHUDA" /><summary type="html"><![CDATA[추가 실습 환경 구촉 pyenv 설치 django를 활용하기 위해 pyenv를 설치해야 되는데 이는 파이썬 가상 환경을 관리할 수 있게 해주는 소프트웨어이다 먼저 아래와 같은 프로그램을 설치해야 된다 다음은 아래와 같이 pyenv를 설치할 수 있다 홈 디렉터리에서 아래 명령어를 입력하여 .bashrc 파일이 있는지 확인한다 오호 있다 vim .bashrc 명령어를 입력하여 .bashrc 파일을 아래와 같이 수정한다 아래 명령어를 이용하여 셸을 재시작]]></summary></entry><entry><title type="html">도커와 쿠버네티스 6: 도커를 활용한 Flask 실습</title><link href="https://daniazie.github.io/ms/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A46/" rel="alternate" type="text/html" title="도커와 쿠버네티스 6: 도커를 활용한 Flask 실습" /><published>2024-08-06T00:00:00+09:00</published><updated>2024-08-06T00:00:00+09:00</updated><id>https://daniazie.github.io/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A46</id><content type="html" xml:base="https://daniazie.github.io/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A46/"><![CDATA[<h2 id="실습-환경-구축">실습 환경 구축</h2>
<h3 id="flask-라이브러리-설치">Flask 라이브러리 설치</h3>
<ul>
  <li>Flask: django와 마찬가지로 파이썬을 활용하여 쉽게 웹사이트를 만들 수 있도록 도와주는 웹 프레임워크</li>
  <li>가상 환경을 실행하여 Flask를 설치해본다<img src="/assets/img/posts/docker6/img1.png" alt="photo 1" /></li>
  <li>Flask를 설치한 후 성공적으로 설치되는지 확인 <img src="/assets/img/posts/docker6/img2.png" alt="photo 2" /></li>
</ul>

<h3 id="flask-실행을-위한-네트워크-설정">Flask 실행을 위한 네트워크 설정</h3>
<ul>
  <li>5장과 마찬가지로 VirtualBox에서 포트포워딩 설정에서 인덱스 2개를 아래와 같이 추가한다 <img src="/assets/img/posts/docker6/img3.png" alt="photo 3" /></li>
</ul>

<h3 id="flask로-실행하는-hello-world">Flask로 실행하는 hello world!</h3>
<ul>
  <li>이 실습을 위한 디렉터리를 만든다<img src="/assets/img/posts/docker6/img4.png" alt="photo 4" /></li>
  <li>ex01에 들어가서 myapp이라는 디렉터리를 생성하여 들어가고나서 main.py를 생성하여 아래와 같이 작성한다 
  <img src="/assets/img/posts/docker6/img5.png" alt="photo 5" />
    <ul>
      <li><code class="language-plaintext highlighter-rouge">app = Flask(__name__)</code>: flask 웹 애필리케이션 객체를 app이라고 지정한다</li>
      <li><code class="language-plaintext highlighter-rouge">app.run(host='0.0.0.0', port=8001</code>: 파이썬 스크립트가 실행되면 <code class="language-plaintext highlighter-rouge">app.run</code>  통해 웹 애플리케이션을 실행하도록 정한다
        <ul>
          <li><code class="language-plaintext highlighter-rouge">host='0.0.0.0</code>: 모든 IP주소로부터 요청을 수락하고록 설정하는 옵션</li>
          <li><code class="language-plaintext highlighter-rouge">port=8001</code>: 8001번 포트를 사용하겠다는 의미</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>main.py를 실행해본다 <img src="/assets/img/posts/docker6/img6.png" alt="photo 6" /></li>
  <li>127.0.0.1:8001에 들어가서 실행 결과 확인 <img src="/assets/img/posts/docker6/img7.png" alt="photo 7" /></li>
</ul>

<h2 id="nginx-flask-연동-후-실행">Nginx, Flask 연동 후 실행</h2>
<h3 id="실습-디렉터리-정리">실습 디렉터리 정리</h3>
<ul>
  <li>디렉터리를 아래와 같이 정리한다 <img src="/assets/img/posts/docker6/img8.png" alt="photo 8" /></li>
</ul>

<h3 id="flask-이미지-빌드">Flask 이미지 빌드</h3>
<ul>
  <li>myFlask02에 들어가서 requirements.txt를 작성한다 <img src="/assets/img/posts/docker6/img9.png" alt="photo 9" /></li>
  <li>Dockerfile을 아래와 같이 작성한다 <img src="/assets/img/posts/docker6/img10.png" alt="photo 10" /></li>
</ul>

<h3 id="nginx-이미지-빌드">Nginx 이미지 빌드</h3>
<ul>
  <li>myNginx02f라는 폴더를 생성한다 <img src="/assets/img/posts/docker6/img11.png" alt="photo 11" /></li>
  <li>default.conf 파일을 생성하여 작성한다 <img src="/assets/img/posts/docker6/img12.png" alt="photo 12" /></li>
  <li>Dockerfile을 아래와 같이 작성한다 <img src="/assets/img/posts/docker6/img13.png" alt="photo 13" /></li>
  <li>아래와 같이 이미지를 빌드한다 <img src="/assets/img/posts/docker6/img14.png" alt="photo 14" /></li>
</ul>

<h3 id="flask-nginx-컨테이너-연동">Flask, Nginx 컨테이너 연동</h3>
<ul>
  <li>도커 네트워크 생성 <img src="/assets/img/posts/docker6/img15.png" alt="photo 15" /></li>
  <li>Flask과 Nginx 컨테이너 실행 <img src="/assets/img/posts/docker6/img16.png" alt="photo 16" /></li>
  <li>실행 결과 확인 
  <img src="/assets/img/posts/docker6/img17.png" alt="photo 17" /></li>
</ul>

<h2 id="도커-컴포즈를-활용한-컨테이너-실행">도커 컴포즈를 활용한 컨테이너 실행</h2>
<h3 id="docker-composeyml-파일-작성">docker-compose.yml 파일 작성</h3>
<ul>
  <li>실습 디렉터리 정리 <img src="/assets/img/posts/docker6/img18.png" alt="photo 18" /></li>
  <li>docker-compose.yml 아래와 같이 작성 <img src="/assets/img/posts/docker6/img19.png" alt="photo 19" /></li>
  <li>컨테이너 빌드 및 실행 <img src="/assets/img/posts/docker6/img20.png" alt="photo 20" /></li>
  <li>컨테이너들이 실행 중인지 확인 <img src="/assets/img/posts/docker6/img21.png" alt="photo 21" /></li>
</ul>]]></content><author><name></name></author><category term="Study" /><category term="Docker &amp; Kubernetes" /><category term="KHUDA" /><summary type="html"><![CDATA[실습 환경 구축 Flask 라이브러리 설치 Flask: django와 마찬가지로 파이썬을 활용하여 쉽게 웹사이트를 만들 수 있도록 도와주는 웹 프레임워크 가상 환경을 실행하여 Flask를 설치해본다 Flask를 설치한 후 성공적으로 설치되는지 확인]]></summary></entry><entry><title type="html">도커와 쿠버네티스 2: 도커의 개념</title><link href="https://daniazie.github.io/ms/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A42/" rel="alternate" type="text/html" title="도커와 쿠버네티스 2: 도커의 개념" /><published>2024-08-05T00:00:00+09:00</published><updated>2024-08-05T00:00:00+09:00</updated><id>https://daniazie.github.io/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A42</id><content type="html" xml:base="https://daniazie.github.io/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A42/"><![CDATA[<h2 id="사전-기초-지식">사전 기초 지식</h2>
<h3 id="운영체제의-개념">운영체제의 개념</h3>
<h4 id="컴퓨터란">컴퓨터란?</h4>
<ul>
  <li>하드웨어와 소프트웨어로 구성되어 있다
    <ul>
      <li>하드웨어: 손으로 만질 수 있는 기계 장치 → 하드웨어적 측면에서 컴퓨터는 CPU와 RAM의 모음이라고 생각할 수 있음</li>
      <li>소프트웨어: 하드웨어에서 작동되는 프로그램 → 운영체제는 시스템 소프트웨어임 ⇒ 운영체제가 있어야 프로그램들을 실행할 수 있다 
  ⇒ 운영체제: 하드웨어, 소프트웨 자원을 관리하고 이를 위해 스케줄링 기능을 제공할 뿐만 아니라 프로그램이 실행할 수 있는 환경을 제공하는 역할을 한다</li>
    </ul>
  </li>
</ul>

<table>
  <tbody>
    <tr>
      <td><img src="/assets/img/posts/docker2/img1.png" alt="photo 1" /></td>
      <td>→</td>
      <td><img src="/assets/img/posts/docker2/img2.png" alt="photo 2" /></td>
      <td>→</td>
      <td><img src="/assets/img/posts/docker2/img3.png" alt="photo 3" /></td>
    </tr>
  </tbody>
</table>

<ul>
  <li>컴퓨터가 이렇게 구성되어 있는데
    <ul>
      <li>소프트웨어 ⇒ 애플리케이션 + 운영체제 ⇒ 운영체제 라이브러리 + 그 외 라이브러리 + 커
        <ul>
          <li>운영체제와 애플리케이션 사이에는 셸이 존재하는데 셸은 껍질이라는 뜻 ⇒ 운영체제를 껍질처럼 감싸고 있는 것을 볼 수 있다
            <ul>
              <li>셸: 운영체제와 사용자 사의에서 다리 열할을 하는 프로그램이라고 생각하면 된다 → 이를 통해서 사용자는 명령어를 입력함으로써 운영체제와 상호작용하며 다양한 작업을 할 수 있다.</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<h3 id="프로그램-프로세스-스레드의-개념">프로그램, 프로세스, 스레드의 개념</h3>
<h4 id="그로그램이란">그로그램이란?</h4>
<ul>
  <li>실행 가능한 명령어의 집합임 → 하드 디스크와 같은 저장 장치에 저장되어 있지만 메머리에는 올라가지 않은 정적인 상태
    <h4 id="프로세스란">프로세스란?</h4>
  </li>
  <li>실행 중인 프로그램 → 동적인 상태의 프로그램임</li>
  <li>멀티 프로세스: 디스크에 존쟇는 프로그램을 여러 번 실행하여 여러 개의 프로세스를 작동시키는 것
    <h4 id="프로그램-vs-프로세스">프로그램 vs. 프로세스</h4>
  </li>
</ul>

<table>
  <thead>
    <tr>
      <th>프로그램</th>
      <th>프로세스</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>디스크에 존재하는 명령어 집합</td>
      <td>실행 중인 프로그램이라 램에 존재하는 것</td>
    </tr>
  </tbody>
</table>

<h4 id="스레드란">스레드란?</h4>
<ul>
  <li>프로세스가 할당받은 자원을 이용하는 실행 단위이자 프로세스 내에 실행되는 여러 흐름의 단위임
    <ul>
      <li>프로세스가 최소 한 개 이상의 스레드를 가짐 → 메인 스레드라고 함</li>
      <li>프로세스는 스레드의 컨테이너에 해당한다고 생각하면 됨 → 프로세스는 스레드의 정보를 담고 있는 것이라고 생각할 수 있음</li>
    </ul>
  </li>
</ul>

<h3 id="네임스페이스의-개념">네임스페이스의 개념</h3>
<ul>
  <li>네임스페이스: 프로세스를 실행할 때 시스템 리소스를 분리해서 실행할 수 있도록 도와주는 기능이다</li>
</ul>

<h4 id="리눅스-네임스페이스">리눅스 네임스페이스</h4>

<table>
  <thead>
    <tr>
      <th>네임스페이스</th>
      <th>의미</th>
      <th>역할</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>pid</td>
      <td>PID: Process ID</td>
      <td>니룩스 커널의 프로세스 ID 분리</td>
    </tr>
    <tr>
      <td>net</td>
      <td>NET: Networking</td>
      <td>네트워크 인터페이스(NET) 관리</td>
    </tr>
    <tr>
      <td>ipc</td>
      <td>IPC: Inter Process Communication</td>
      <td>프로세스 간 통신(IPC) 접근 관리</td>
    </tr>
    <tr>
      <td>mnt</td>
      <td>MNT: Mount</td>
      <td>파일 세스템의 마운트 관리</td>
    </tr>
    <tr>
      <td>uts</td>
      <td>UTS: Unix Timesharing System</td>
      <td>커널과 버전 식별자 관리</td>
    </tr>
  </tbody>
</table>

<ul>
  <li>각각의 기능을 확용하면 프로세스를 격리시켜 충돌을 방지할 수 있다</li>
</ul>

<h2 id="도커-기초-지식">도커 기초 지식</h2>
<h3 id="도커의-정의">도커의 정의</h3>
<ul>
  <li>도커: 회사도 의미하고, 소프트웨어도 의미함
    <h4 id="소프트웨어로서의-도커">소프트웨어로서의 도커</h4>
  </li>
  <li>컨테이너라고 부르는 운영체제 수준의 가상화 방식으로 소프트웨어를 배포하는 방식을 사용하는 PaaS 제폼임
    <ul>
      <li>PaaS: 애플리케이션, 데이터 단계만 사용자가 관리하는 서비스임 ⇒ 도커를 사용해서 다양한 개발 환경에서 컨테이너를 이용하여 소프트웨어를 편리하게 배포할 수 있다는 것</li>
    </ul>
  </li>
  <li>오픈소스임</li>
  <li>도커를 활용한 애플리케이션 실행:
    <ul>
      <li>운영체제 위에 도커가 설치되고 도커는 컨테이너 단위로 애플리케이션을 실행하게 되는데 컨테이너들은 서로 격리되어 있으므로 독립성을 보장함 → 각 컨테이너는 애플리케이션을 실행하는 데 필요한 최소한의 바이너리, 라이브러리가 포함된다</li>
    </ul>
  </li>
</ul>

<h3 id="컨테이너의-개념">컨테이너의 개념</h3>
<ul>
  <li>컨테이너: 소프트웨어를 배포할 때 필요한 코드, 라이브러리, 환경 설정 파일들을 한 데 모아 격리시킨 후 실행 가능한 패키지로 만드는 것</li>
  <li>서로 다른 컨테이너는 격리된 환경에서 작동되므로 서로 충둘하지 않는다는 장점이 있다
    <ul>
      <li>소프트웨어 시스템을 구축할 때 최소 구성 요소로 분할하여 구축하는 방식 → 마이크로서비스 아키텍처</li>
    </ul>
  </li>
  <li>컨테이너가 동일한 운영체제 위에서 작동해서 격리된 서로 다른 컨테이너들끼리는 통신을 주고받을 수 있다 → 가상머신에 비해 리소스 소모량이 적으므로 효율족인 리소스 관리가 가능</li>
</ul>

<h3 id="가상화의-개념">가상화의 개념</h3>
<ul>
  <li>가상화: 컴퓨터에서 활용하는 시로스를 추상화하는 개념 → 이를 활용하여 여러 개의 가상머신을 생성함으로써, 단일 컴퓨팅 자원을 여러 개의 논리적인 자원으로 나누어 동작시킬 수 있다
    <h4 id="호스트-가상화">호스트 가상화</h4>
  </li>
  <li>운영체제를 설치한 후 하이퍼바이저를 통해 가상머신을 만들고 각 가상머신 내부에는 게스트 운영체제가 설치된다
    <ul>
      <li>하이퍼바이저: 단일 물리 모신에서 다수의 가상머신을 실행할 때 활용하는 소프트웨어임</li>
    </ul>
  </li>
  <li>Ex: VirtualBox, VMWare, 등등</li>
  <li>많이 사용한다
    <h4 id="하이퍼바이저-가상화">하이퍼바이저 가상화</h4>
  </li>
  <li>호스트 운영체제를 필요로 하지 않는 방식에 해당함 → 존재하지 않으므로 부팅 시 가상머신을 선택하게 된다</li>
  <li>성능이 우수하다는 장점 있지만 초기 설정이 복잡하고 관리가 어려울 수 있다는 단점도 있다
    <h4 id="컨테이너-가상화">컨테이너 가상화</h4>
  </li>
  <li>운영체제 위에 컨테이너를 운영하기 위해 필요한 도커를 설치한 후 다수의 컨테이너를 통해 애플리케이션을 실행하는 방식이다</li>
  <li>Ex: Docker, Kubernetes, 등등</li>
  <li>이 방식을 사용하면 컨테이너 간 격리가 되어서 다른 애플리케이션에 영향을 미치지 않아 서로 다른 컴퓨팅 화경에서 애플리케이션을 실행하는 데 용이한다</li>
</ul>

<h3 id="도커-구성-요소">도커 구성 요소</h3>
<h4 id="도커-클라이언트">도커 클라이언트</h4>
<ul>
  <li>docker-cli라고 부르는데 우분투에서 실행하는 터미널이라고 생각하면 된다
    <ul>
      <li>명령어 행으로 dockerd API를 활용하여 <code class="language-plaintext highlighter-rouge">build</code>, <code class="language-plaintext highlighter-rouge">pull</code>, <code class="language-plaintext highlighter-rouge">run</code> 과 같은 명령을 내린다</li>
      <li>도커 데몬과 통신한다
        <h4 id="도커-데몬">도커 데몬</h4>
      </li>
    </ul>
  </li>
  <li>dockerd라고 부르는데 백그라운드에서 실행되는 데몬 프로세스에 해당한다</li>
  <li>도커 API 요청을 수신하고 도커 이미지, 컨테이너 등과 같은 도커와 관련된 객체를 관리한다
    <h4 id="containerd">containerd</h4>
  </li>
  <li>컨테이너 실행과 관리에 필요한 기능을 수행하는 컨테이너 런타임 → 컨테이너의 생명주기를 모두 관리한다
    <ul>
      <li>생명주기: 도커 이미지 전송, 컨테이너 실행, 스토리지, 네트워크 등 포함됨</li>
    </ul>
  </li>
  <li>컨테이너 실행만 담당하는 runc와는 다른 역할을 하며 고수준 컨테이너 런타임에 해당한다
    <h4 id="runc">runc</h4>
  </li>
  <li>컨테이너 실행과 관련된 작업을 수행하는 저수준 컨테이너 런타임 → 실제 컨테이너 실행만 담당
    <h4 id="containerd-shim">containerd-shim</h4>
  </li>
  <li>containerd와 runc 사이에서 작동하는 중간 프로세스에 해당하는데, 컨테이너 실행을 조정하는 역할을 한다</li>
  <li>containerd는 runc와 통신함으로써 컨테이너 실행 → containerd-shim이 둘이 사이에서 중개자 역할 수행</li>
</ul>]]></content><author><name></name></author><category term="Study" /><category term="Docker &amp; Kubernetes" /><category term="KHUDA" /><summary type="html"><![CDATA[사전 기초 지식 운영체제의 개념 컴퓨터란? 하드웨어와 소프트웨어로 구성되어 있다 하드웨어: 손으로 만질 수 있는 기계 장치 → 하드웨어적 측면에서 컴퓨터는 CPU와 RAM의 모음이라고 생각할 수 있음 소프트웨어: 하드웨어에서 작동되는 프로그램 → 운영체제는 시스템 소프트웨어임 ⇒ 운영체제가 있어야 프로그램들을 실행할 수 있다 ⇒ 운영체제: 하드웨어, 소프트웨 자원을 관리하고 이를 위해 스케줄링 기능을 제공할 뿐만 아니라 프로그램이 실행할 수 있는 환경을 제공하는 역할을 한다 → →]]></summary></entry><entry><title type="html">도커와 쿠버네티스 3: 도커 설치</title><link href="https://daniazie.github.io/ms/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A43/" rel="alternate" type="text/html" title="도커와 쿠버네티스 3: 도커 설치" /><published>2024-08-05T00:00:00+09:00</published><updated>2024-08-05T00:00:00+09:00</updated><id>https://daniazie.github.io/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A43</id><content type="html" xml:base="https://daniazie.github.io/posts/%EB%8F%84%EC%BB%A4%EC%99%80-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A43/"><![CDATA[<h2 id="사전-준비-사항">사전 준비 사항</h2>
<ul>
  <li><a href="https://docs.docker.com/engine/install/ubuntu">Docker Docs</a> 참고</li>
  <li>일단 필요한 도커 리포지토리와 통신할 수 있는 환경을 설정해봐야 되어서 PuTTY에서 명령어를 입력했다 <img src="/assets/img/posts/docker3/img1.png" alt="photo 1" />
    <ul>
      <li><code class="language-plaintext highlighter-rouge">sudo apt-get update</code>: apt 패키지 인덱스를 업데이트한다는 명령어</li>
      <li><code class="language-plaintext highlighter-rouge">sudo apt-get install ca-certificates curl gnupg lsb-release</code>: apt가 HTTPS에서 리포지토리를 사용할 수 있게 하는 데 필요한 패키리를 설치하는 과정이다
        <ul>
          <li>ca-certificates: 인증서 관련 패키지</li>
          <li>curl: 파일을 다운로드하기 위한 패키지</li>
          <li>gnupg: 디지털 서명을 사용하기 위한 패키지</li>
          <li>lsb-release: 리눅스 배포판 식별능 뉘해 필요한 패키지
  → 설치해봤을 때 다 설치된다고 했다.</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>다음에는 아래 코드를 입룍하여 도커 공식 GPG 키를 추가하게 된다 <img src="/assets/img/posts/docker3/img2.png" alt="photo 2" />
    <ul>
      <li>GPG는 GNU Privacy Guard이라고 하는데, 도커 이미지 인증을 확인할 때 사용하는 키이</li>
    </ul>
  </li>
  <li>그리고 아래와 같이 리포지토리를 설정했다 <img src="/assets/img/posts/docker3/img3.png" alt="photo 3" /></li>
</ul>

<h2 id="도커-설치">도커 설치</h2>
<ul>
  <li>도커를 정상적으로 설치하기 위해 apt 패키지를 다시 업데이트해야 된다 <img src="/assets/img/posts/docker3/img4.png" alt="photo 4" /></li>
  <li>아래 명령을 입력한 후 도커 설치 과정을 시작하게 되는데, 설치하는 중 계속할거냐고 할 때 Y를 입력하면 설치 과정이 계속 진행된다 <img src="/assets/img/posts/docker3/img5.png" alt="photo 5" /></li>
  <li>도커가 성공적으로 설치가 되었는지 확인하겠다. <img src="/assets/img/posts/docker3/img6.png" alt="photo 6" />
    <ul>
      <li>되었구만만</li>
    </ul>
  </li>
  <li>도커 잘 작동되어 있는지 확인하겠다<img src="/assets/img/posts/docker3/img7.png" alt="photo 7" /></li>
  <li>아래 코드를 실행해서 도커 명령어를 사용자 모드에서도 사용할 수 있도록 한다 <img src="/assets/img/posts/docker3/img8.png" alt="photo 8" /></li>
  <li><code class="language-plaintext highlighter-rouge">docker version</code>을 입력하면 도커 버전을 확인할 수 있다<img src="/assets/img/posts/docker3/img9.png" alt="photo 9" />
    <ul>
      <li>권한이 없다는데 우분투 서버에 로그아웃했다가 다시 로그인해봐야 겠다 <img src="/assets/img/posts/docker3/img10.png" alt="photo 10" />
        <ul>
          <li>오호 됐다</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<h2 id="hello-world">hello world</h2>
<ul>
  <li>도커를 설치했으니 도커가 원활하게 작동하는지 테스트하겠다. <img src="/assets/img/posts/docker3/img11.png" alt="photo 11" />
    <ul>
      <li>확인했다!</li>
    </ul>
  </li>
</ul>]]></content><author><name></name></author><category term="Study" /><category term="Docker &amp; Kubernetes" /><category term="KHUDA" /><summary type="html"><![CDATA[사전 준비 사항 Docker Docs 참고 일단 필요한 도커 리포지토리와 통신할 수 있는 환경을 설정해봐야 되어서 PuTTY에서 명령어를 입력했다 sudo apt-get update: apt 패키지 인덱스를 업데이트한다는 명령어 sudo apt-get install ca-certificates curl gnupg lsb-release: apt가 HTTPS에서 리포지토리를 사용할 수 있게 하는 데 필요한 패키리를 설치하는 과정이다 ca-certificates: 인증서 관련 패키지 curl: 파일을 다운로드하기 위한 패키지 gnupg: 디지털 서명을 사용하기 위한 패키지 lsb-release: 리눅스 배포판 식별능 뉘해 필요한 패키지 → 설치해봤을 때 다 설치된다고 했다. 다음에는 아래 코드를 입룍하여 도커 공식 GPG 키를 추가하게 된다 GPG는 GNU Privacy Guard이라고 하는데, 도커 이미지 인증을 확인할 때 사용하는 키이 그리고 아래와 같이 리포지토리를 설정했다]]></summary></entry></feed>