<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>도커 &#8211; WONIZZ.LOG</title>
	<atom:link href="https://blog.wonizz.com/tag/%EB%8F%84%EC%BB%A4/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.wonizz.com</link>
	<description>DEVELOPMENT &#38; LIFE LOG</description>
	<lastBuildDate>Fri, 21 Aug 2026 15:46:25 +0000</lastBuildDate>
	<language>ko-KR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.2</generator>

<image>
	<url>https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2026/08/wz-siteicon-512.png?fit=32%2C32&#038;ssl=1</url>
	<title>도커 &#8211; WONIZZ.LOG</title>
	<link>https://blog.wonizz.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">152411368</site>	<item>
		<title>[DevOps] ELK를 활용한 로그 분석</title>
		<link>https://blog.wonizz.com/2019/10/07/elk-log-anlysis/</link>
					<comments>https://blog.wonizz.com/2019/10/07/elk-log-anlysis/#respond</comments>
		
		<dc:creator><![CDATA[워니]]></dc:creator>
		<pubDate>Mon, 07 Oct 2019 13:59:37 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[공부]]></category>
		<category><![CDATA[도커]]></category>
		<guid isPermaLink="false">http://blog.wonizz.tk/?p=835</guid>

					<description><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
<p>안녕하세요? 정리하는 개발자 워니즈입니다. 이번시간에는 ELK를 활용한 웹서버 로그 분석에 대해서 알아보는 시간을 갖도록 해보겠습니다. 필자가 운영하는 프로젝트에서는 Nginx(IDS &#8211; Internet Detection Server) 와 Apache(웹서버) &#8211; WAS 서버의 구성으로 이루어져있습니다. Apache에서는 whitelist된 URL query string 에 대해서만 캐시를 남기고 그외에는 WAS까지 접속하여 가져오는 구성으로 되어어 있습니다. (식별된 파라미터에 대해서는 캐싱된 페이지를 보여주기 위함 입니다.) 그러다보니,&#8230;&#160;</p>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/10/07/elk-log-anlysis/">[DevOps] ELK를 활용한 로그 분석</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
안녕하세요? 정리하는 개발자 워니즈입니다. 이번시간에는 <code>ELK</code>를 활용한 웹서버 로그 분석에 대해서 알아보는 시간을 갖도록 해보겠습니다.

필자가 운영하는 프로젝트에서는 Nginx(IDS &#8211; Internet Detection Server) 와 Apache(웹서버) &#8211; WAS 서버의 구성으로 이루어져있습니다.

Apache에서는 whitelist된 URL query string 에 대해서만 캐시를 남기고 그외에는 WAS까지 접속하여 가져오는 구성으로 되어어 있습니다. (식별된 파라미터에 대해서는 캐싱된 페이지를 보여주기 위함 입니다.)

그러다보니, 비식별된 파라미터들의 접속량이 증가하면 WAS 서버에 부하를 주게 되어 이를 모니터링 할 수 있는 프로세스를 생각해봤습니다.

그러던중 <code>ELK</code>를 알게 되었고, filebeat와 logstash를 적절하게 이용하면 로그분석을 통하여 비식별 파라미터를 추출해 낼 수 있을 것이라고 생각했습니다.

<h1>1. 로그 수집 프로세스</h1>

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/10/ELK_%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98.png?w=1200&#038;ssl=1" alt="DevOps ELK를 활용한 로그 분석 설명 이미지 1" />

<ol>
<li>아파치 혹은 Nginx의 access.log에 외부 접근이 생기면 정해진 로그 포맷에 따라 파일이 생성되거나 내용이 추가됩니다.</li>
<li>filbeat는 마치 리눅스의 tail명령어와 같이 지속적으로 파일을 읽어서 로그스태시에게 전달해줍니다. filebeat.yml 파일의 설정 파일로 target 로그스태시 지정이 가능합니다.</li>
<li>logstash에서 input 모듈을 활용하면 beat에서의 내용을 받을 수 있습니다. 반드시 앞에 filebeat가 있어야 되는것이 아니고 로컬의 파일을 읽을 수도 있고, 혹은 외부 json 호출도 가능합니다.</li>
<li>logstash의 강력한 기능중 하나인 filter를 통하여 log파일의 정제 및 reform이 가능합니다.</li>
<li>정제된 내용을 elastic으로 output으로 보내 줍니다.</li>
<li>키바나에서는 elastic의 내용을 표현해줍니다.</li>
</ol>

<h1>2. Docker-elk를 활용한 설치</h1>

지금까지 <code>Docker</code>에 대해서 학습을 해왔기 때문에 Docker로 설치해보고자합니다. 개별제품군으로 설치를 하면 귀찮지만, Docker를 한번에 <code>ELK</code> 스택을 한번에 올릴 수 있어 굉장히 편합니다.

<h2>2-1. docker-elk repository clone</h2>

작업 디렉토리에서 docker-elk git 레포지토리를 clone 합니다.

<pre><code class="line-numbers">$ git clone https://github.com/deviantony/docker-elk#requirements
</code></pre>

<a href="https://github.com/deviantony/docker-elk" target="_blank" rel="noopener">docker-elk</a>

<h2>2-2. configuration</h2>

docker-elk를 clone 받으면 docker-elk 폴더가 생기고 여기서 각 config 폴더 안에 elk에 대한 설정을 해주면됩니다.

<ul>
<li>elasticsearch.yml</li>
<li>logstash.yml / logstash.conf</li>
<li>kibana.yml</li>
</ul>

<h2> </h2>

<h2>2-3. docker-elk 실행</h2>

<pre><code class="line-numbers"># docker-compose.yml이 있는 디렉토리에서 수행해야 한다 
# build 
$ docker-compose build 

# 빌드를 통해 생성된 도커 이미지 확인 
$ docker images 

# up: 컨테이너 생성 및 구동, -d는 백그라운드로 실행 옵션 
$ docker-compose up -d 

# 컨테이너 목록 확인 
$ docker-compose ps 

# 컨테이너 로그 확인 
$ docker-compose logs -f
</code></pre>

컨테이너 목록 확인에 정상적으로 컨테이너 3개(elasticsearch, logstash, kibana)가 보이고, 로그에서도 문제가 없으면 정상적으로 작동된 것이다. 브라우저에서 localhost:5601로 접속하면 kibana 웹 UI 화면이 뜰 것이다.

<h2>2-4. filebeat 설치</h2>

elk에 대한 내용은 설치를 완료했고, 필자 같은 경우, filebeat는 직접 host에 설치를 했습니다.

<ul>
<li>filebeat 설치

filebeat 를 yum을 통해서 설치

<pre><code class="line-numbers">sudo rpm --import https://packages.elastic.co/GPG-KEY-elasticsearch
</code></pre>

/etc/yum.repods.d/elastic.repo 추가

<pre><code class="line-numbers">[elastic-6.x]
name=Elastic repository for 6.x packages
baseurl=https://artifacts.elastic.co/packages/6.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md
</code></pre></li>
</ul>

​   <code>yum install filebeat</code>를 통해서 설치를 진행합니다.

<h1>3. 설정</h1>

이제 각 설정을 통해서 연결을 해줍니다.

<h2>3-1. filebeat 설정</h2>

filebeat 에서는 json 형태로 logstash 에게 데이터를 전달하고, 이때 <code>message</code> 필드에 수집한 로그 파일의 데이터가 담겨진다. 수집하려는 log file 의 유형에 따라서 <a href="https://www.elastic.co/guide/en/beats/libbeat/current/community-beats.html" target="_blank" rel="noopener">community beats</a>를 사용할 수도 있지만, 필자의 경우에는 Custom pattern의 로그 파일을 수집할 예정이라 logstash에서 pasring 하는 형태를 선택했다.

<pre><code class="line-numbers">![ELK_로그스태시](http://blog.wonizz.com/wp-content/uploads/2019/10/ELK_로그스태시.png)filebeat.prospectors:

# Each - is a prospector. Most options can be set at the prospector level, so
# you can use different prospectors for various configurations.
# Below are the prospector specific configurations.

- type: log
  enabled: true
  paths:
    - /var/log/my_log_path/*.log
  fields:
    index_name: "my_custom_file_index_name"

#----------Elasticsearch output--------------- 주석처리
# (beats 에서 바로 ES 로 데이터 전달하지 않음)


#----------Logstash output ------------------- 주석해제
# (beats 에서 logstash 로 데이터 전달)

output.logstash:
  # The Logstash hosts
  hosts: ["my-logstash-server-host:5044"]

...
</code></pre>

filebeat는 굉장히 심플하다. 1)target으로 보내주는 파일지정과 2) target에 대한 셋팅만 하면된다. 필자가 처음에 애먹었던 부분은 위에 보이는 것과 같이 elastic으로 바로 전달하면 안되기에 주석처리를 하고 logstash를 열어줘야되는데, logstash에 host만 셋팅하고 안되는 이유를 한참이나 찾았다.

<h2>3-2. logstash 설정</h2>

<ul>
<li>grok, mutate, json, geoip, alter 필터를 설정했고 filebeat 에서 fields 로 넘겨받은 index_name을 사용했다.</li>
<li>date 필터는 기준 시각을 filebeat 에 의해서 파싱된 시각을 사용하지 않고, log 에 기록된 시각으로 지정하도록 한다.</li>
</ul>

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/10/ELK_%EB%A1%9C%EA%B7%B8%EC%8A%A4%ED%83%9C%EC%8B%9C.png?w=1200&#038;ssl=1" alt="DevOps ELK를 활용한 로그 분석 설명 이미지 2" />

로그스태시의 기본구저는 INPUT, FILTERS, OUTPUT으로 이루어져있습니다.

<pre><code class="line-numbers">input {
...
}


filter {
...
}


output {
...
}
</code></pre>

아래는 필자가 만든 pipeline입니다. 파이프라인 설정을 통해서 비트로부터 넘어온 로그를 정정제하고 elasticsearch로 보내줍니다.

<pre><code class="line-numbers">input {
  beats {
    port => 5044
  }
}
filter {

        grok {
                match => { "message" => "\"(?:%{WORD:verb} %{GREEDYDATA:uri_stem}\?%{GREEDYDATA:uri_query}(?: HTTP/%{NUMBER:httpversion})?|-)\" %{QS:agent}" }
        }
        if "_grokparsefailure" in [tags] {
                drop { }
        }
        mutate {
                gsub => [ "uri_query", "=(?<=\=)(.*?)(?=&#038;|HTTP)", "",
                           "uri_query", "HTTP/1.0", "",
                           "uri_query", "HTTP/1.1", "",
                           "uri_query", "nocache", "",
                           "uri_query", "kkkkk", ""
        ]
                split => { "uri_query" => "&" }
        }
        mutate {
                remove_field => "message"
                remove_field => "verb"
                remove_field => "httpversion"
         }
        date {
                 match => [ "timestamp" , "dd/MMM/yyyy:HH:mm:ss Z" ]
        }

}
output {
        elasticsearch {
                hosts => ["172.26.0.1:9200"]
                index => "wonizz_nginx"
                user => "elastic"
                password => "changeme"
        }

                stdout { codec => rubydebug }
}
</code></pre>

하나씩 의미를 확인해보겠습니다.

<ul>
<li>input</li>
</ul>

<pre><code class="line-numbers">beats {
    port => 5044
  }
</code></pre>

내용에서 보다시피, filebeat로부터 오는 input에 대한 내용입니다. 기본적으로 5044 tcp 포트로 들어오는 데이터를 수집합니다.

<ul>
<li>filter</li>
</ul>

<pre><code class="line-numbers">grok {
                match => { "message" => "\"(?:%{WORD:verb} %{GREEDYDATA:uri_stem}\?%{GREEDYDATA:uri_query}(?: HTTP/%{NUMBER:httpversion})?|-)\" %{QS:agent}" }
        }
</code></pre>

grok은 넘어오는 input에 대하여 동적으로 mapping하여 각 포맷별로 mapping시켜주는 것입니다. 예를들어 아파치나 nginx의 access.log는 정해진 포맷이 있는데 적절하게 grok 패턴을 사용하면 알아서 매핑을 해주어 쪼개줍니다.

아래의 2가지 웹사이트를 활용하여 필자는 custom되어있는 nginx로그를 매핑할 수 있는 grok 패턴을 만들어 봤습니다.

<a href="https://grokdebug.herokuapp.com/" target="_blank" rel="noopener">grok debugger</a>

<a href="https://grokconstructor.appspot.com/" target="_blank" rel="noopener">grok constructor</a>

<pre><code class="line-numbers">if "_grokparsefailure" in [tags] {
                drop { }
        }
</code></pre>

단순히, grok mapping에 실패하였을 경우, continue 하는 내용입니다.

<pre><code class="line-numbers">mutate {
                gsub => [ "uri_query", "=(?<=\=)(.*?)(?=&#038;|HTTP)", "",
                           "uri_query", "HTTP/1.0", "",
                           "uri_query", "HTTP/1.1", "",
                           "uri_query", "nocache", "",
                           "uri_query", "kkkkk", ""
        ]
                split => { "uri_query" => "&" }
        }
</code></pre>

mutate는 그 의미에서도 알 수 있듯이 변형을 가하는 것입니다.

gsub는 substring을 하는 것이고, split은 쪼개는 것입니다.
위에서 보는 내용은 uri_query로 매핑되어 도출된 내용을 적절하게 substring하여 앰퍼센트(&amp;)로 쪼개는 내용입니다.

예를들어, uri_query string이 &#8220;test=1&amp;test2=2 HTTP/1.1&#8243; 이라고 들어오면 첫줄의 정규식에 의하여 test&amp;test2 HTTP/1.1&#8221; 이 남고 그다음부터는 substring으로 제거해줍니다.

test&amp;test2는 split에 의하여 test, test2로 쪼개어 수집하게 됩니다.

<pre><code class="line-numbers">mutate {
                remove_field => "message"
                remove_field => "verb"
                remove_field => "httpversion"
         }
</code></pre>

불필요한 field에 대해서 삭제 처리합니다.

<ul>
<li>output</li>
</ul>

<pre><code class="line-numbers"> elasticsearch {
                hosts => ["172.26.0.1:9200"]
                index => "wonizz_nginx"
                user => "elastic"
                password => "changeme"
        }

</code></pre>

elasticsearch 로 적절한 index로 넣게 됩니다. 여기서 host 같은 경우는 docker로 올렸기 때문에 해당 호스트이 docker daemon 의 network 를 호출하여 9200포트로 보내줍니다.

<h1>4. elasticsearch 조회</h1>

필자 같은경우는 elasticsearch에 넣고 kibana로 조회를 했지만, 알람을 주기 위해 zabbix를 활용했다.

먼저 nodejs를 활용하여 elastic에서 데이터를 조회합니다.

<pre><code class="line-numbers">var elasticsearch = require('elasticsearch');
var client = new elasticsearch.Client({
  host: 'localhost:9200',
  log: 'trace'
});


client.search({
index: 'wonizz_nginx',
type: '_doc',
body: {
"query": {
    "bool": {
      "must": [
        {
          "range": {
            "@timestamp": {
              "gte": "now-1h/h",
              "lte": "now"
            }
          }
        }
      ]
    }
  },
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "uri_query.keyword"
        }
     }
  }
}
})
</code></pre>

간단하게 elasticsearch 모듈을 import하여 조회를 손쉽게 할 수 있다.

필자가 하고자 했던것은 <code>1시간 이전</code>의 데이터를 수집한 뒤, <code>aggregation</code>을 이용하여 uri_query에 대해서 group by를 하고자 하는 것입니다.

앞서 이야기했듯이 whitelist되지 않은 parameter가 노출이 되면, 해당 내용을 .log파일로 출력하고, zabbix는 지속적으로 .log파일을 감시하다가 신규 내용이 올라오면, 알람을 주는 구조입니다.

elasticsearch <-> nodejs -> requset_parameter.log 파일 &lt;- zabbix 감시

<h1>5. 마치며&#8230;</h1>

이번시간에는 <code>ELK</code>와 Filebeat를 통해서 로그 수집에 대해서 알아봤습니다. 아직은 기초적인 단계이지만, 잘만 활용하면 전체적인 로그의 모습을 볼 수 있고 또한 access.log같은 경우 패턴도 분석이 가능할 것 같습니다.

<code>ELK</code> 스택에서 제공해주는 로그 패턴 분석으로 알람까지 주는 기능도 좀더 알아봐야될 것 같습니다.

다음이시간에는 Elasticsearch 클러스터 구성에 대해서 알아보는 시간을 갖도록 하겠습니다.
<h2 class="wp-block-heading">함께 보면 좋은 글</h2>
<ul class="wp-block-list"><li><a href="https://blog.wonizz.com/2019/02/26/devops-assign/">DevOps 사전 과제</a></li><li><a href="https://blog.wonizz.com/2019/09/06/aws-ecs/">[AWS] ECS  서비스란?</a></li><li><a href="https://blog.wonizz.com/2019/08/08/ansible-role-include/">[Ansible] 플레이북 Role 과 Include</a></li><li><a href="https://blog.wonizz.com/2019/08/21/kubernetes-service/">[Kubernetes] 쿠버네티스 Service 란?</a></li></ul>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/10/07/elk-log-anlysis/">[DevOps] ELK를 활용한 로그 분석</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.wonizz.com/2019/10/07/elk-log-anlysis/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">835</post-id>	</item>
		<item>
		<title>[AWS] ECS  서비스란?</title>
		<link>https://blog.wonizz.com/2019/09/06/aws-ecs/</link>
					<comments>https://blog.wonizz.com/2019/09/06/aws-ecs/#respond</comments>
		
		<dc:creator><![CDATA[워니]]></dc:creator>
		<pubDate>Fri, 06 Sep 2019 05:35:20 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[도커]]></category>
		<guid isPermaLink="false">http://blog.wonizz.tk/?p=762</guid>

					<description><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
<p>안녕하세요? 정리하는 개발자 워니즈 입니다. 이번시간에는 아마존에서 제공하는 서비스중 하나인 ECS에 대해서 정리를 해보려고 합니다. 기존에 EC2 인스턴스 내에서 도커를 설치하고 컨테이너를 생성해보는것을 해봤는데요. 기존에 SWARM이라던지, 쿠버네티스와 같은 서비스는 없을까 하고 알아보던중에 아마존에서 제공해주는 서비스가 있다는 것을 알게 되었습니다. ECS 는 elastic container service의 약자로 클러스터를 구성해주고 컨테이너를 생성해주고 관리해주는 역할을 합니다. 1. 클러스터의 개념&#8230;&#160;</p>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/09/06/aws-ecs/">[AWS] ECS  서비스란?</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
안녕하세요? 정리하는 개발자 워니즈 입니다. 이번시간에는 아마존에서 제공하는 서비스중 하나인 <code>ECS</code>에 대해서 정리를 해보려고 합니다. 기존에 EC2 인스턴스 내에서 도커를 설치하고 컨테이너를 생성해보는것을 해봤는데요. 기존에 SWARM이라던지, 쿠버네티스와 같은 서비스는 없을까 하고 알아보던중에 아마존에서 제공해주는 서비스가 있다는 것을 알게 되었습니다. <code>ECS</code> 는 elastic container service의 약자로 클러스터를 구성해주고 컨테이너를 생성해주고 관리해주는 역할을 합니다.

<h2>1. 클러스터의 개념</h2>

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/09/DOCKER_Cluster.png?w=1200&#038;ssl=1" alt="AWS ECS  서비스란? 설명 이미지 1" />

<code>ECS</code>의 가장 기본적인 단위는 클러스터입니다. 클러스터는 도커 컨테이너를 실행할 수 있는 가상의 공간입니다. 클러스터를 잘 구분해주는 것이 중요한데, 보통 프로젝트 단위나 업무(service) 단위로 구분지어 생성합니다.

<h2>2. Task Definition</h2>

<code>ECS</code> 에서 컨테이너를 실행하는 최소 단위를 <code>태스크</code> 라고 합니다. 태스크는 하나 이상의 컨테이너로 구성이 됩니다. 여러 컨테이너의 조합으로 하나의 <code>태스크</code>를 생성 할 수 있스니다. 태스크를 실행하려면 <code>태스크 디피니션</code>이 필요합니다. <code>네트워크 모드</code>, <code>태스크 역할</code>, <code>도커 이미지</code>, <code>실행 명령어</code>, <code>CPU 제한</code>, <code>메모리 제한</code> 등 다수의 설정이 필요합니다. 컨테이너를 오케스트레이션을 사용하는 가장큰 이유중 하나는 컨테이너의 생명주기를 스스로 관리하게끔 하는 것입니다. 이러한 설정들의 정의를 미리 작성해두어, 나중에 이 정의를 기반으로 태스크를 실행합니다.

<h2>3. 서비스</h2>

태스크를 실행하는 방식은 다음 두가지 입니다.

<ul>
<li>태스크 디피니션을 통한 태스크 실행</li>
<li>서비스 정의</li>
</ul>

서비스는 하나의 태스크 디피니션(리비전)과 연결됩니다. 서비스 타입은 다시 다음 두가지 방식으로 나뉘어 집니다.

<ul>
<li>데몬타입</li>
<li>리플리카 타입</li>
</ul>

데몬타입 같은 경우는 각 인스턴스 별로 1개의 컨테이너가 생성이 되고, 리플리카 같은 경우는 태스크의 개수를 지정하여 클러스터에서 이 개수만큼 태스크가 실행되도록 자동적으로 관리를 해줍니다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/09/ECS_SERVICE.png?w=1200&#038;ssl=1" alt="AWS ECS  서비스란? 설명 이미지 2" />

서비스는 <code>ECS</code> 클러스터 내에서 작업을 스케쥴링 해주는 역할을 합니다. EC2와 같은 컴퓨팅 자원을 직접 사용해서 프로세스를 배치하는 경우 서버 운영자가 직접 어떤 인스턴스에 어떤 프로세스를 언제 배치할지 결정해야합니다. 오케스트레이션에서는 이러한 관리를 담당하는 스케줄러가 존재합니다. ECS에서는 서비스가 이러한 스케줄링을 담당하고 있습니다. ECS 서비스는 각 인스턴스들에 설치된 ecs-client에서 수집된 정보를 기반으로 어디에 어떤 태스크를 언제 실행할지 결정합니다. 따라서 리플리카 타입 서비스의 경우, 다수의 컨테이너 인스턴스가 있을 때 언제 어디에서 태스크가 실행될지 알 수 없습니다. 서비스가 직접 태스크 배치 스케줄링을 수행합니다.*

<h2>4. ECR(Elastic Container Registry)</h2>

AWS ECS에서는 엘라스틱 컨테이너 레지스트리ECR, Elastic Container Registry라는 프라이빗 도커 레지스트리 서비스를 제공하고 있습니다. 도커 레지스트리는 도커 이미지를 저장 및 관리하는 서비스입니다. 일반적으로 도커에서 공식적으로 제공하는 도커 허브Docker Hub가 많이 이용됩니다. 이미지를 비공개적로 푸시하거나 풀하는 경우에는 도커 허브의 유료 플랜을 이용하거나 직접 도커 레지스트리 서비스를 운용해야합니다. ECR을 사용해서 프라이빗 도커 레지스트리를 대체할 수 있으며, IAM과 조합함으로서 세세한 권한 관리가 가능합니다.

<h2>5. 실습 예제</h2>

필자의 프로젝트에서는 아직 Container를 운영하고 있지는 않습니다. 하지만, ECR을 한번 고려해보기 위해서 실습예제를 수행해보도록 하겠습니다.

<h3>5-1. 클러스터 생성</h3>

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/09/ECS_CLUSTER_1.png?w=1200&#038;ssl=1" alt="AWS ECS  서비스란? 설명 이미지 3" />

아마존의 ECR 메뉴로 들어가게 되면, 클러스터를 생성할 수 있는 메뉴가 있습니다. 거기서 EC2+네트워킹을 선택하여 필요한 모든 resource들을 생성해줍니다. 필자 같은 경우는 아래와 같이 생성했습니다.

<ul>
<li>클러스터 인스턴스 2대</li>
<li>VPC / Subnet</li>
<li>Security Group</li>
<li>IAM</li>
</ul>

IAM 같은 경우는 아래의 내용때문에 필요합니다. > Amazon ECS 컨테이너 에이전트는 사용자를 대신하여 Amazon ECS API 작업을 호출하므로 에이전트가 사용자에게 속한다는 것을 서비스가 알기 위해서는 에이전트를 실행하는 컨테이너 인스턴스에 ecsInstanceRole IAM 정책과 역할이 필요합니다. ecsInstanceRole이 아직 없는 경우, AWS가 생성할 수 있습니다.

<h3>5-2. ECR 생성</h3>

이미지들을 관리하기 위해서 Repository를 구성해주어야 합니다. 아마존에서는 손쉽게 ECR로 생성이 가능합니다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/09/ECR_%EC%83%9D%EC%84%B1.png?w=1200&#038;ssl=1" alt="AWS ECS  서비스란? 설명 이미지 4" />

<h3>5-3. 이미지 생성</h3>

이미지 생성을 해볼 시간입니다. Dockerfile을 작성한 뒤에 이미지 빌드를 수행해서 나오는 이미지를 ECR에 push해보는 작업까지 해보겠습니다.

<pre><code>
FROM richarvey/nginx-php-fpm:1.5.3
RUN echo '<!DOCTYPE html><html lang="ko">' > /var/www/html/index.php ;\
    echo '<style>html{ margin: 10rem; }</style>' >> /var/www/html/index.php ;\
    echo '<h1>Nginx Demo v0.1</h1>' >> /var/www/html/index.php ;\
    echo '<h2>Hostname: <?php echo gethostname() ?></h2>' >> /var/www/html/index.php ;\
    echo '</html>' >> /var/www/html/index.php

</code></pre>

<pre><code>$ docker build -t wonni/nginx:v0.1 .
</code></pre>

<h3>5-4. ERC 푸시</h3>

위의 작업을 통해서 이미지가 생서잉 되면, ECR로 이미지를 push해야합니다.

로그인

<pre><code>(aws ecr get-login --no-include-email --region ap-northeast-1)
</code></pre>

푸시할 이미지 준비

<pre><code>docker tag wonni/nginx:latest 194506033013.dkr.ecr.ap-northeast-1.amazonaws.com/first-repository:latest
</code></pre>

푸시

<pre><code>docker push 194506033013.dkr.ecr.ap-northeast-1.amazonaws.com/first-repository:latest
</code></pre>

<h3>5-5. 작업 정의</h3>

위에서 이야기했던 <code>Task Definition</code>을 정의할 단계입니다. 아마존 콘솔에서 진행은 하되, <code>JSON</code>을 통한 구성을 클릭하여 다음을 입력해줍니다.

<pre><code class="line-numbers">{
  "family": "ecs_nginx_examaple",
  "networkMode": "bridge",
  "containerDefinitions": [
    {
      "name": "nginx",
      "essential": true,
      "image": "194506033013.dkr.ecr.ap-northeast-1.amazonaws.com/first-repository:latest",
      "cpu": 0,
      "memory": 128,
      "portMappings": [
        {
          "hostPort": 80,
          "containerPort": 80,
          "protocol": "tcp"
        }
      ]
    }
  ]
}

</code></pre>

위의 작업 정의를 보면 알겠지만, 어떤 이미지를 사용하고 자원할당은 어떤식으로 하고 PORT구성은 어떻게 되어있는지에 대한 정의서 작성단계입니다.

<h3>5-6. 서비스 생성</h3>

이제 태스크 정의까지 완료 되었으니, 이를 스케쥴링 해주는 <code>서비스</code>를 생성해야합니다. 아마존 콘솔에서 클러스터 > 서비스 탭에서 생성 버튼을 클릭해줍니다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/09/ECS_Service_%EC%83%9D%EC%84%B1.png?w=1200&#038;ssl=1" alt="AWS ECS  서비스란? 설명 이미지 5" />

그러면, 어떠한 작업 정의를 기준으로 어떻게 배포를 하는지에 대한 선택을 하는 창이 나옵니다. 최종적으로 완성된 아키텍처는 아래와 같습니다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/09/ECS_%EC%99%84%EB%A3%8C.png?w=1200&#038;ssl=1" alt="AWS ECS  서비스란? 설명 이미지 6" />

아직 ELB는 연결하지 않았지만, ELB를 생성하여 TargetGroup으로 클러스터링된 EC2 인스턴스를 넣어주면 됩니다.

<blockquote>
  여기서 만약에 Task definition 에서 container replica를 4개를 주면 어떻게 될까요? 
  현재 Container가 80포트를 점유하고 있기때문에, 2개만 생성이 되고 2개의 Container는 exited code 0로 생성되지 않습니다. 그러면 이러한 상황을 어떻게 해결할 수 있을까요? 

container cluster전체를 하나의 port(80)로 바인딩하고 내부 container는 random port로 줘서 port forwarding으로 해결할 수 있습니다.
</blockquote>

<h3>5-7. ALB 생성</h3>

필자는 ECR을 학습하면서 그림에서 ELB 생성이 나타나 있지만, 아마존에서 권고하는것은 msa 와 alb간에 port forwarding기능으로 상호작용이 좋다고 합니다. 그래서 필자는 ALB를 생성했습니다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/09/ECS_ALB.png?w=1200&#038;ssl=1" alt="AWS ECS  서비스란? 설명 이미지 7" />

보이시는것처럼 리스너에 대상그룹을 추가해줬습니다. 그럼 위에서 나온 80포트로 ALB로 들어오면 80으로 대상그룹으로 보내서 Container 서비스를 할 수 있습니다.

<h3>5-8. Task Definition 수정 및 서비스 재배포</h3>

위에서 정의한 <code>작업 정의</code>를 업데이트 합니다. <code>새 개정 생성</code> 을 클릭 한뒤에 json을 클릭하여 HOST 포트를 0으로 바꺼줍니다. 그렇게 되면, Nginx가 생성될때 임의의 포트를 생성하게 됩니다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/09/ECS_%EC%9E%91%EC%97%85%EC%A0%95%EC%9D%98.png?w=1200&#038;ssl=1" alt="AWS ECS  서비스란? 설명 이미지 8" />

이제 서비스를 재생성합니다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/09/ECS_%EC%84%9C%EB%B9%84%EC%8A%A4%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8.png?w=1200&#038;ssl=1" alt="AWS ECS  서비스란? 설명 이미지 9" />

보시는 것처럼 위에서 수정한 <code>작업 정의</code>가 버전 <code>2</code>로 변경되어 있습니다. 이것을 지정합니다. 네트워크 탭에서는 앞서 생성한 <code>ALB</code>를 지정하여 ecs에서 인식하도록 합니다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/09/ECS_%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC.png?w=1200&#038;ssl=1" alt="AWS ECS  서비스란? 설명 이미지 10" />

이제 생성한 서비스가 배포가 됩니다. 최종적으로 ALB내용이 포함된 서비스를 배포하고 나면, ALB에서는 동적으로 포트포워딩을 Target Group으로 지정하여 생성되게 됩니다. 따라서 아래와 같은 그림으로 서비스 하게 됩니다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/09/ECS_%EC%B5%9C%EC%A2%85.png?w=1200&#038;ssl=1" alt="AWS ECS  서비스란? 설명 이미지 11" />

<h2>6. 마치며..</h2>

이번 글을 작성하면서, 기존에 도커 컨테이너를 학습하고 오케스트레이션에 관한 학습도 이어서 진행을 했었는데 아마존에서는 이미 서비스로 손쉽게 클러스터링을 하고 배포를 할 수 있도록 구성이 다 되어있다는 점에서 놀랐습니다. ECR + ECS를 통해서 컨테이너관리를 손쉽게 할 수 있을 뿐만 아니라, 유연성있게 서비스를 운영할 수 있을것 같다는 생각을 했습니다. 다음시간에는 EKS에 대해서 간단히 정리해보는 시간을 갖도록 하겠습니다.
<h2 class="wp-block-heading">함께 보면 좋은 글</h2>
<ul class="wp-block-list"><li><a href="https://blog.wonizz.com/2019/08/16/kubenetes-install-guide/">[Kubernetes] 쿠버네티스 설치와 사용법</a></li><li><a href="https://blog.wonizz.com/2019/07/31/docker-dockerfile/">[Docker] Dockerfile 의 이해</a></li><li><a href="https://blog.wonizz.com/2019/08/21/kubernetes-service/">[Kubernetes] 쿠버네티스 Service 란?</a></li><li><a href="https://blog.wonizz.com/2019/08/08/ansible-role-include/">[Ansible] 플레이북 Role 과 Include</a></li></ul>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/09/06/aws-ecs/">[AWS] ECS  서비스란?</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.wonizz.com/2019/09/06/aws-ecs/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">762</post-id>	</item>
		<item>
		<title>[Kubernetes] 쿠버네티스 Service 란?</title>
		<link>https://blog.wonizz.com/2019/08/21/kubernetes-service/</link>
					<comments>https://blog.wonizz.com/2019/08/21/kubernetes-service/#comments</comments>
		
		<dc:creator><![CDATA[워니]]></dc:creator>
		<pubDate>Wed, 21 Aug 2019 05:36:48 +0000</pubDate>
				<category><![CDATA[kubernetes]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[도커]]></category>
		<guid isPermaLink="false">http://blog.wonizz.tk/?p=752</guid>

					<description><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
<p>안녕하세요? 정리하는 개발자 워니즈 입니다. 지난시간에는 쿠버네티스 POD라는 개념에 대해서 알아봤는데요. 이번시간에는 이러한 POD들을 어떻게 서비스를 해주는 지에 대한 관점인 Service에 대해서 알아보는 시간을 가져보도록 하겠습니다. 지난 글들은 아래를 참고 해주시면 됩니다. 쿠버네티스 1편 : 설치 가이드 쿠버네티스 2편 : pod 쿠버네티스 3편 : service 쿠버네티스 4편 : deployment 쿠버네티스 5편 : pod 설정 쿠버네티스&#8230;&#160;</p>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/08/21/kubernetes-service/">[Kubernetes] 쿠버네티스 Service 란?</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
<p>안녕하세요? 정리하는 개발자 워니즈 입니다. 지난시간에는 쿠버네티스 <code>POD</code>라는 개념에 대해서 알아봤는데요. 이번시간에는 이러한 <code>POD</code>들을 어떻게 서비스를 해주는 지에 대한 관점인 <code>Service</code>에 대해서 알아보는 시간을 가져보도록 하겠습니다.</p>
<p>지난 글들은 아래를 참고 해주시면 됩니다.</p>
<ul>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/08/16/kubenetes-install-guide/">쿠버네티스 1편 : 설치 가이드</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/08/19/kubernetes-pod/">쿠버네티스 2편 : pod</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/08/21/kubernetes-service/">쿠버네티스 3편 : service</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/09/17/kubernetes-deployment/">쿠버네티스 4편 : deployment</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/10/28/kubernetes-pod-configuration/">쿠버네티스 5편 : pod 설정 </a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/11/01/kubernetes-deployment-strategies/">쿠버네티스 6편 : 배포 전략</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/11/07/kubernetes-volume/">쿠버네티스 7편 : volume</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/11/15/kubernetes-daemonset/">쿠버네티스 8편 : daemonset</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/11/27/kubernetes-cluster-terraform/">쿠버네티스 9편 : 테라폼을 통한 클러스터 구성</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/11/28/kubernetes-aws-eks-volume/">쿠버네티스 10편 : eks에서 volume 사용하기</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/12/20/kubernetes-helm/">쿠버네티스 11편 : helm</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2020/01/03/kubernetes-helm-chart-template/">쿠버네티스 12편 : helm chart template</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2020/01/14/kubernetes-helm-deploy/">쿠버네티스 13편 : helm deploy</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2020/05/26/kubernetes-fluentd-logging/">쿠버네티스 14편 : fluentd를 통한 log수집</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2020/06/03/kubernetes-helm-chartmuseum/">쿠버네티스 15편 : chartmuseum</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2020/06/05/kubernetes-deploy-tool-argocd/">쿠버네티스 16편 : 배포툴(ArgoCD 설치방법/사용법)</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="https://blog.wonizz.com/2020/06/15/kubernetes-deploy-tool-notification//">쿠버네티스 17편 : 배포툴(ArgoCD 구성/알람)</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2020/08/24/kubernetes-autoscaling-hpa/">쿠버네티스 18편 : 쿠버네티스 Autoscailing</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="https://blog.wonizz.com/2020/10/14/kubernetes-logging-architecture/">쿠버네티스 19편 : 쿠버네티스 로깅 아키텍처</a></li>
</ul>
<p>필자가 속한 프로젝트에서는 아직 쿠버네티스를 사용하고 있지 않습니다. 그래서 개인적으로 쿠버네티스 클러스터를 연결해서 nginx POD 를 생성해서 배포까지 해봤습니다. 그런데 여기서 <code>POD</code> 가 여러개라면 그 앞에 관문 역할을 하는 것이 필요할 것입니다.</p>
<p>이러한 개념이 바로 <code>Service</code> 입니다.</p>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/K8S_Service_architecture.png?w=1200&#038;ssl=1" alt="Kubernetes 쿠버네티스 Service 란? 설명 이미지 1" /></p>
<h2>1. Service Template 작성</h2>
<p>서비스 템플릿이란 쿠버네티스에서 <code>Service</code>를 생성하기 위한 <code>YML</code> 로 작성된 파일을 말합니다. 다음은 예시입니다.</p>
<pre><code class="line-numbers">apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 80
    protocol: TCP
  selector:
    run: my-nginx
</code></pre>
<p>그럼 위의 내용을 한줄 씩 설명해드리겠습니다.</p>
<ul>
<li>서비스 이름</li>
</ul>
<pre><code class="line-numbers">metadata:
  name: my-nginx

</code></pre>
<p>서비스의 이름은 <code>my-nginx</code>이고, <code>labels</code>는 해당 POD에 대해서 라벨링을 해두는것인데, 여기서는 <code>run: my-nginx</code>라고 해두었습니다.</p>
<ul>
<li>타입</li>
</ul>
<pre><code class="line-numbers">spec:
  type: NodePort

</code></pre>
<p><code>Service</code>는 유형(<code>ClusterIP</code>, <code>NodePort</code>, <code>LoadBalancer</code>) 을 갖고 있는데, <code>Node Port</code>를 여기서 사용하고있습니다.</p>
<ul>
<li>포트</li>
</ul>
<pre><code class="line-numbers">  ports:
  - port: 8080
    targetPort: 80
    protocol: TCP
</code></pre>
<p>클러스터 port는 <code>8080</code> 이고 실제 nginx POD가 서비스 되는 포트는 <code>80</code> 포트입니다.</p>
<ul>
<li>셀렉터</li>
</ul>
<pre><code class="line-numbers">  selector:
    run: my-nginx
</code></pre>
<p>이 서비스는 Pod중에서 label 값이 <code>run: my-nginx</code> 인 pod쪽으로 서비스 합니다.</p>
<h2>2. Service Object 의 특징</h2>
<ul>
<li>서비스 타입 종류
<ul>
<li>Cluster IP</li>
<li>NodePort</li>
<li>LoadBalancer</li>
</ul>
</li>
<li>Label Selector 통해서 Pod 타겟팅 + 로드밸런싱</li>
<li>Service yaml 파일에 기술된 name로 쿠버네티스 클러스터상에 DNS를 생성할 수 있습니다.</li>
</ul>
<h3>2-1. 서비스 타입</h3>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/K8S_Service_type.png?w=1200&#038;ssl=1" alt="Kubernetes 쿠버네티스 Service 란? 설명 이미지 2" /></p>
<ol>
<li>ClusterIP : 쿠버네티스의 디폴트 설정으로 외부에서 접근가능한 IP를 할당받지 않기 때문에 Cluster내에서만 해당 서비스를 노출할 때 사용되는 Type</li>
<li>NodePort : 해당 서비스를 외부로 노출시키고자 할 때 사용되는 Service Type으로 외부에 Node IP와 Port를 노출시키는 것으로 아래 그림과 같이 쿠버네티스 클러스터 상에 있는 모든 노드(VM)에 대해서 노출 시킵니다.</li>
</ol>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/K8S_Service_nodeport.png?w=1200&#038;ssl=1" alt="Kubernetes 쿠버네티스 Service 란? 설명 이미지 3" /></p>
<ol start="3">
<li>LoadBalancer : 클라우드상에 존재하는 LoadBalancer에 연결하고자 할 때 사용되는 Service Type으로 LoadBalancer의 외부 External IP를 통해 접근이 가능합니다.</li>
</ol>
<h3>2-2. 서비스 네임 : DNS</h3>
<p>Kubernetes는 자체 DNS서버를 가지고 있어 클러스터 내부에서만 사용가능한 DNS를 설정해서 사용할 수 있습니다. 이것은 Kubernetes상에서 통신할때 IP기반이 아닌 DNS를 통해 연결할 수 있음을 뜻하며 아래 그림과 같이 Pod에서 다른 Pod의 서비스를 연결할때 사용됩니다.</p>
<h2>3. Ingress</h2>
<p>Ingress는 Kubernetes v1.1 추가된 기능으로 <code>NodePort</code> 와<code>LoadBalancer</code> 와 마찬가지로 애플리케이션의 Service를 외부로 노출할때 사용되는 리소스입니다.</p>
<p>외부에서 들어온 HTTP와 HTTPS 트래픽을 ingress resouce를 생성하여 Cluster내부의 Service로 L7영역에서 라우팅하며  로드밸런싱, TLS, 도메인 기반의 Virtual Hosting을 제공합니다.</p>
<p>이러한 기능은 NodePort로 서비스를 노출하는 것에 비해 외부의 서비스를 보다 손쉽게 관리할 수 있도록해줍니다.</p>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/matthewpalmer.net/kubernetes-app-developer/articles/ingress.png?w=1200&#038;ssl=1" alt="Kubernetes 쿠버네티스 Service 란? 설명 이미지 4" /></p>
<p>Ingress는 실질적인 라우팅 기능을 제공하는 Ingress Controller와 Ingress  리소스로 구성할 수 있는데, ingress 리소스는 외부의 URLs을 Cluster 내부의 Service로 라우팅하는 rule이 정의되어 있으며, Ingress Controller에는 다양한 구현체가 존재하며, 여기서는 nginx ingress controller를 설치해 실습해 보도록하겠습니다.</p>
<h3>3-1. Single Service Ingress</h3>
<pre><code class="line-numbers">apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: single-ingress
spec:
  backend:
    serviceName: my-nginx-svc
    servicePort: 80
</code></pre>
<pre><code class="line-numbers">root@master:/lab/service/ingress# kubectl get ingress
NAME             HOSTS   ADDRESS         PORTS   AGE
single-ingress   *       192.168.1.240   80      2m17s
root@master:/lab/service/ingress# curl http://192.168.1.240
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.

For online documentation and support please refer to
<a href="http://nginx.org/" target="_blank" rel="noopener">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/" target="_blank" rel="noopener">nginx.com</a>.

<em>Thank you for using nginx.</em>
</body>
</html>
</code></pre>
<h2>4. 실습</h2>
<p>앞서 이야기했던 <code>Service</code> 들에 대해서 개별적으로 실습해보는 내용들을 정리해보겠습니다. 우선 아래와 같이 폴더 구조를 생성하였고, 각 타입에 맞추어 <code>pod</code>과 <code>serivce</code>를 생성하여 실습을 했습니다.</p>
<pre><code class="line-numbers">lab
 └── service
     │
     ├── clusterip
     │   ├── nginx-pod.yaml
     │   └── nginx-svc.yaml
     │
     ├── loadbalancer
     │   ├── nginx-pod.yaml
     │   └── nginx-svc.yaml
     │
     └── nodeport
         ├── nginx-pod.yaml
         └── nginx-svc.yaml

# pod & service 배포
# cd /lab/sercie/{servicetype폴더}
# kubectl apply -f .

</code></pre>
<h3>4-1. Cluster IP</h3>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/K8S_Service_Clusterip.png?w=1200&#038;ssl=1" alt="Kubernetes 쿠버네티스 Service 란? 설명 이미지 5" /></p>
<ul>
<li>파드 생성하기</li>
</ul>
<pre><code class="line-numbers">root@master:~# gedit /lab/service/clusterip/nginx-pod.yaml

</code></pre>
<pre><code class="line-numbers">apiVersion: v1
kind: Pod
metadata:
  labels:
    run: my-nginx
  name: my-nginx-pod
  namespace: default
spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: my-nginx-container
    ports:
    - containerPort: 80
      protocol: TCP

</code></pre>
<ul>
<li>서비스 생성하기</li>
</ul>
<pre><code class="line-numbers">root@master:~# kubectl apply -f /lab/service/clusterip

</code></pre>
<ul>
<li>결과 확인</li>
</ul>
<p>Service를 조회해보면 Cluster 내부에서만 사용가능한 Cluster IP가 할당된 것을 확인 할 수 있으며, 클러스터에서 curl 명령을 통해 접근가능한 것을 확인 할 수 있습니다.</p>
<pre><code class="line-numbers">root@master:/lab# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR
kubernetes     ClusterIP   172.168.1.1     <none>        443/TCP   80m   <none>
my-nginx-svc   ClusterIP   172.168.1.240   <none>        80/TCP    74m   run=my-nginx

root@master:/lab# kubectl describe svc my-nginx-svc
Name:              my-nginx-svc
Namespace:         default
Labels:            run=my-nginx
Annotations:       kubectl.kubernetes.io/last-applied-configuration:
                     {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"run":"my-nginx"},"name":"my-nginx-svc","namespace":"default"},...
Selector:          run=my-nginx
Type:              ClusterIP
IP:                172.168.1.240        # ClusterIP
Port:              <unset>  80/TCP      # Cluster Port
TargetPort:        80/TCP               # Container Port
Endpoints:         10.32.0.5:80         # Container IP
Session Affinity:  None
</code></pre>
<ul>
<li>파드 DNS</li>
</ul>
<pre><code class="line-numbers">[ root@curl-5cc7b478b6-rjq5d:/ ]$ nslookup my-nginx-svc
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      my-nginx-svc
Address 1: 10.101.62.208 my-nginx-svc.default.svc.cluster.local

[ root@curl-5cc7b478b6-kb8w8:/ ]$ curl my-nginx-svc.default.svc.cluster.local
</code></pre>
<p>이러한 내부 DNS로 아래 그림과 같이 Pod에서 다른 서비스 또는 다른 Pod로 통신이 가능합니다.</p>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/K8S_Service_architecture.png?w=1200&#038;ssl=1" alt="Kubernetes 쿠버네티스 Service 란? 설명 이미지 6" /></p>
<ul>
<li>Namespaces and DNS</li>
</ul>
<p>Service Object를 생성하면 해당 Service의 name으로 <namespace-name>를 포함해 아래와 같은 규칙을 가진 DNS가 cluster 내에 생성됩니다. 이것은 어떤 container(pod)에서 해당 service를 DNS로 호출하는 경우에  개발계, 운영계 등과 같이 multiful namespace를 구성했을때 동일한 설정의 구성을 가능하게 합니다. 이것은 만약 다른 namespace 예를 들면 개발계에서 운영계의 Service를 호출하고자 할때는 FQDN을 사용해야 한다는 뜻입니다.</p>
<pre><code class="line-numbers"><service-name>.<namespace-name>.svc.cluster.local 

</code></pre>
<h3>4-2. NodePort</h3>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/K8S_Service_type.png?w=1200&#038;ssl=1" alt="Kubernetes 쿠버네티스 Service 란? 설명 이미지 7" /></p>
<ul>
<li>파드 생성하기</li>
</ul>
<pre><code class="line-numbers">root@master:~# gedit /lab/service/nodeport/nginx-pod.yaml
</code></pre>
<pre><code class="line-numbers">apiVersion: v1
kind: Pod
metadata:
  labels:
    run: my-nginx
  name: my-nginx-pod
  namespace: default
spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: my-nginx-container
    ports:
    - containerPort: 80
      protocol: TCP
</code></pre>
<ul>
<li>서비스 생성하기</li>
</ul>
<pre><code class="line-numbers"># gedit /lab/service/nodeport/nginx-svc.yaml
</code></pre>
<pre><code class="line-numbers">apiVersion: v1
kind: Service
metadata:
  name: my-nginx-svc
  labels:
    run: my-nginx
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 80
    protocol: TCP
  selector:
    run: my-nginx
</code></pre>
<pre><code class="line-numbers">kubectl apply -f /lab/service/nodeport/
</code></pre>
<ul>
<li>결과 확인</li>
</ul>
<p>NodePort로 service를 생성하게 되면 자동으로 3XXXX대의 포트를 확인 할 수 있습니다. 이 Port가 모든 VM에 노출된 Node Port이고 Cluster 외부인 어느 VM에서나 접근이 가능합니다.</p>
<pre><code class="line-numbers">root@master:/lab# kubectl get svc
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
my-nginx-svc   NodePort    172.168.1.240   <none>        8080:31331/TCP   140m


root@master:/lab# kubectl describe svc my-nginx-svc
Name:                     my-nginx-svc
Namespace:                default
Labels:                   run=my-nginx
Annotations:              kubectl.kubernetes.io/last-applied-configuration:
                            {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"run":"my-nginx"},"name":"my-nginx-svc","namespace":"default"},...
Selector:                 run=my-nginx
Type:                     NodePort
IP:                       172.168.1.240       # Cluster IP
Port:                     <unset>  8080/TCP   # Cluster Port
TargetPort:               80/TCP              # Container Port
NodePort:                 <unset>  31331/TCP  # Node Port
Endpoints:                10.32.0.5:80        # Container IP, Port
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

> VM IP로 접근
# curl localhost:31331

> Mater, Node 등 모든 node VM내의 Firefox에서 아래 url로 접근가능
http://localhost:31331

</code></pre>
<h3>4-3. LoadBalancer</h3>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/K8S_Service_type.png?w=1200&#038;ssl=1" alt="Kubernetes 쿠버네티스 Service 란? 설명 이미지 8" /></p>
<ul>
<li>파드 생성하기</li>
</ul>
<pre><code class="line-numbers">root@master:~# gedit /lab/service/loadbalancer/nginx-pod.yaml

</code></pre>
<pre><code class="line-numbers">apiVersion: v1
kind: Pod
metadata:
  labels:
    run: my-nginx
  name: my-nginx-pod
  namespace: default
spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: my-nginx-container
    ports:
    - containerPort: 80
      protocol: TCP
</code></pre>
<ul>
<li>서비스 생성하기</li>
</ul>
<pre><code class="line-numbers"># gedit /lab/service/loadbalancer/nginx-svc.yaml
</code></pre>
<pre><code class="line-numbers">apiVersion: v1
kind: Service
metadata:
  name: my-nginx-svc
  labels:
    run: my-nginx
spec:
  type: LoadBalancer
  ports:
  - port: 3000
    targetPort: 80
    protocol: TCP
  selector:
    run: my-nginx
</code></pre>
<pre><code class="line-numbers">kubectl apply -f /lab/service/loadbalancer
</code></pre>
<ul>
<li>결과 확인</li>
</ul>
<p>VM상에 가상으로 설치한 loadbalancer에 서비스가 매핑된것을 확인 할 수 있습니다.</p>
<p>가상으로 설치한 loadbalancer의 IP는 192.168.1.240 이며, Cluster상에서 해당IP로 nginx 서비스에 접근이 가능합니다.(crul http://192.168.1.240:8080), 이 IP는 실제 클라우드 상에서는 클라우드 벤더가 제공하는 로드밸런서 장비의 외부로 노출된 공인IP입니다.</p>
<pre><code class="line-numbers">root@master:/lab/service/loadbalancer# kubectl get svc
NAME           TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
kubernetes     ClusterIP      172.168.1.1     <none>          443/TCP          7m1s
my-nginx-svc   LoadBalancer   172.168.1.240   192.168.1.240   3000:30947/TCP   30s

root@master:/lab/service/loadbalancer# kubectl describe svc my-nginx-svc
Name:                     my-nginx-svc
Namespace:                default
Labels:                   run=my-nginx
Annotations:              kubectl.kubernetes.io/last-applied-configuration:
                            {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"run":"my-nginx"},"name":"my-nginx-svc","namespace":"default"},...
Selector:                 run=my-nginx
Type:                     LoadBalancer
IP:                       172.168.1.240
LoadBalancer Ingress:     192.168.1.240
Port:                     <unset>  3000/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30947/TCP
Endpoints:                10.32.0.5:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:
  Type    Reason       Age   From                Message
  ----    ------       ----  ----                -------
  Normal  IPAllocated  44s   metallb-controller  Assigned IP "192.168.1.240"

root@master:/lab/service/loadbalancer# curl http://192.168.1.240:3000
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
</code></pre>
<ul>
<li>외부 네임 생성하기</li>
</ul>
<p>여기서는 추가적으로 외부에 노출되는 name에 대해서 정리했습니다.</p>
<pre><code class="line-numbers"># gedit /lab/service/external/external-svc.yaml
</code></pre>
<pre><code class="line-numbers">kind: Service
apiVersion: v1
metadata:
  name: myservice
spec:
  type: ExternalName
  externalName: www.github.com
  ports:
  - port: 80
</code></pre>
<p>오브젝트 생성</p>
<pre><code class="line-numbers">kubectl apply -f /lab/service/external/external-svc.yaml
</code></pre>
<h2>5. 마치며..</h2>
<p>필자가 쿠버네티스의 개념에 대해서 정리를 하면서 한개씩 실습을 진행했는데, 위의 내용중 <code>Service</code>의 유형에 대해서 시도해보다가, <code>NodePort</code>만으로 실습을 진행했습니다.</p>
<p>필자가 원하는 방향은 외부에 노출되는 port에 대해서는 fix시켜서 지정을 하고싶어, <code>LoadBalancer</code>타입으로 해봤으나, <code>External-IP</code>가 <code>Pending</code>상태가 지속되면서 연결이 안되었습니다.</p>
<p>또한, <code>Ingress</code> layer를 service 앞단에 연결하였으나, 역시 동작하지 않았습니다.<br />
이부분에 대해서 현재 정리중이며, 위의 내용을 보완해서 정리하도록 하겠습니다.</p>
<p><a href="http://blog.wonizz.com" title="워니즈 블로그">워니즈 블로그</a><br />
<a href="http://github.com/wonizz" title="워니즈 깃헙" target="_blank" rel="noopener">워니즈 깃헙</a></p>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/08/21/kubernetes-service/">[Kubernetes] 쿠버네티스 Service 란?</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.wonizz.com/2019/08/21/kubernetes-service/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">752</post-id>	</item>
		<item>
		<title>[Kubernetes] 쿠버네티스 설치와 사용법</title>
		<link>https://blog.wonizz.com/2019/08/16/kubenetes-install-guide/</link>
					<comments>https://blog.wonizz.com/2019/08/16/kubenetes-install-guide/#respond</comments>
		
		<dc:creator><![CDATA[워니]]></dc:creator>
		<pubDate>Fri, 16 Aug 2019 04:46:06 +0000</pubDate>
				<category><![CDATA[kubernetes]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[도커]]></category>
		<guid isPermaLink="false">http://blog.wonizz.tk/?p=742</guid>

					<description><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
<p>안녕하세요? 정리하는 개발자 워니즈입니다. 이번시간에는 쿠버네티스의 설치와 사용법에 대해서 알아보고자합니다. 지난 글들은 아래를 참고 해주시면 됩니다. 쿠버네티스 1편 : 설치 가이드 쿠버네티스 2편 : pod 쿠버네티스 3편 : service 쿠버네티스 4편 : deployment 쿠버네티스 5편 : pod 설정 쿠버네티스 6편 : 배포 전략 쿠버네티스 7편 : volume 쿠버네티스 8편 : daemonset 쿠버네티스 9편 : 테라폼을&#8230;&#160;</p>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/08/16/kubenetes-install-guide/">[Kubernetes] 쿠버네티스 설치와 사용법</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
<p>안녕하세요? 정리하는 개발자 워니즈입니다. 이번시간에는 쿠버네티스의 설치와 사용법에 대해서 알아보고자합니다.</p>
<p>지난 글들은 아래를 참고 해주시면 됩니다.</p>
<ul>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/08/16/kubenetes-install-guide/">쿠버네티스 1편 : 설치 가이드</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/08/19/kubernetes-pod/">쿠버네티스 2편 : pod</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/08/21/kubernetes-service/">쿠버네티스 3편 : service</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/09/17/kubernetes-deployment/">쿠버네티스 4편 : deployment</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/10/28/kubernetes-pod-configuration/">쿠버네티스 5편 : pod 설정 </a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/11/01/kubernetes-deployment-strategies/">쿠버네티스 6편 : 배포 전략</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/11/07/kubernetes-volume/">쿠버네티스 7편 : volume</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/11/15/kubernetes-daemonset/">쿠버네티스 8편 : daemonset</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/11/27/kubernetes-cluster-terraform/">쿠버네티스 9편 : 테라폼을 통한 클러스터 구성</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/11/28/kubernetes-aws-eks-volume/">쿠버네티스 10편 : eks에서 volume 사용하기</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2019/12/20/kubernetes-helm/">쿠버네티스 11편 : helm</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2020/01/03/kubernetes-helm-chart-template/">쿠버네티스 12편 : helm chart template</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2020/01/14/kubernetes-helm-deploy/">쿠버네티스 13편 : helm deploy</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2020/05/26/kubernetes-fluentd-logging/">쿠버네티스 14편 : fluentd를 통한 log수집</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2020/06/03/kubernetes-helm-chartmuseum/">쿠버네티스 15편 : chartmuseum</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2020/06/05/kubernetes-deploy-tool-argocd/">쿠버네티스 16편 : 배포툴(ArgoCD 설치방법/사용법)</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="https://blog.wonizz.com/2020/06/15/kubernetes-deploy-tool-notification//">쿠버네티스 17편 : 배포툴(ArgoCD 구성/알람)</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="http://blog.wonizz.com/2020/08/24/kubernetes-autoscaling-hpa/">쿠버네티스 18편 : 쿠버네티스 Autoscailing</a></li>
<li><input style="margin-right:5px" type="checkbox" class="task-list-item-checkbox" checked disabled /><a class="wp-editor-md-post-content-link" href="https://blog.wonizz.com/2020/10/14/kubernetes-logging-architecture/">쿠버네티스 19편 : 쿠버네티스 로깅 아키텍처</a></li>
</ul>
<p>기존에는 docker swarm으로 클러스터를 구성하였는데요. 구글에서 만든 쿠버네티스를 사용해보고자 합니다.</p>
<p>Kubeadm을 사용하여 Kubernetes 클러스터를 구성하는 방법에 대해 설명합니다. Kubernetes는 아래 그림과 같이 Worker Node에 명령을 내리는 Master Node와 실제 Container가 구동되는 Worker Node로 구성되어 있습니다.</p>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.risingstack.com/content/images/2018/05/kubernetes-worker-node.png?w=1200&#038;ssl=1" alt="Kubernetes 쿠버네티스 설치와 사용법 설명 이미지 1" /></p>
<p>아래 설치과정에서 주의해야 할것은</p>
<ul>
<li>가이드에서는 Master Node 1대와 Work Node 1대를 가정해서 설치를 가이드합니다.(총 VM 2대)</li>
</ul>
<h2>1. 설치전 작업</h2>
<p>기본적으로 쿠버네티스는 컨테이너를 클러스터링 해주는 도구이다보니, 도커가 사전에 설치되어있어야 합니다. 또한, 마스터와 워커노트(VM 2대)가 준비되어있어야 합니다.</p>
<ul>
<li>swap disable</li>
</ul>
<p>Swap 은 메모리가 부족하거나 절전 모드에서 디스크의 일부 공간을 메모리처럼 사용하는 기능입니다. Kubelet 이 정상 동작할 수 있도록 해당 기능을 swap 디바이스와 파일 모두 disable 합니다.</p>
<pre><code class="line-numbers">swapoff -a
echo 0 > /proc/sys/vm/swappiness
sed -e '/swap/ s/^#*/#/' -i /etc/fstab

swapoff -a: paging 과 swap 기능을 끕니다.
/proc/sys/vm/swappiness: 커널 속성을 변경해 swap을 disable 합니다.
/etc/fastab: Swap을 하는 파일 시스템을 찾아 disable 합니다.
</code></pre>
<ul>
<li>노드간 방화벽 해제</li>
</ul>
<p>각 노드의 통신을 원활하게 하기 위해 방화벽 기능을 해제합니다.</p>
<pre><code class="line-numbers">systemctl disable firewalld
systemctl stop firewalld
</code></pre>
<ul>
<li>net filter 모듈 활성화</li>
</ul>
<p>br_netfilter 모듈이 활성화되어 있어야 합니다. modprobe br_netfilter 명령어로 해당 모듈을 명시적으로 추가하고, lsmod | grep br_netfilter 명령어로 추가 여부를 확인할 수 있습니다.</p>
<pre><code class="line-numbers">modprobe br_netfilter
</code></pre>
<p>필자는 net fillter를 활성화 하지 않아서, 오류가 발생했었는데요. /proc/sys/net/bridge 하위의 bridge-nf-call-iptables 파일이 활성화 되어있어야 합니다.</p>
<p>실제로 참고했던 내용입니다 .</p>
<pre><code class="line-numbers">https://stackoverflow.com/questions/44125020/cant-install-kubernetes-on-vagrant
sudo bash -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'
modprobe br_netfilter
echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables
echo 1 > /proc/sys/net/bridge/bridge-nf-call-ip6tables
sudo sysctl -p
</code></pre>
<ul>
<li>도커 설치</li>
</ul>
<p>컨테이너 실행 환경인 도커(Docker)를 설치하고 실행합니다. 쿠버네티스는 도커 외에도 여러가지 CRI(Container Runtime Interface) 구현체를 지원하기 때문에 도커에 종속적이지 않습니다.[1]</p>
<p>필자의 도커 설치 가이드를 참고 부탁드립니다.</p>
<ul>
<li>selinux 권한 제어</li>
</ul>
<p>SELinux(Security-Enhanced Linux)는 리눅스 보안 모듈로 액세스 권한을 제어합니다. 쿠버네티스에서는 컨테이너가 호스트의 파일시스템에 접속할 수 있도록 해당 기능을 꺼야 합니다.</p>
<pre><code class="line-numbers">setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
</code></pre>
<h2>2. 쿠버네티스 설치하기</h2>
<p>본격적으로 쿠버네티스를 설치해보겠습니다.</p>
<ul>
<li>repository 수정</li>
</ul>
<pre><code class="line-numbers">cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kube*
EOF
</code></pre>
<ul>
<li>yum 을 통한 설치</li>
</ul>
<pre><code class="line-numbers">yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
systemctl enable kubelet && systemctl start kubelet
</code></pre>
<ul>
<li>마스터 노드 초기화</li>
</ul>
<p>이제 Master 노드에 컨트롤 구성 요소를 설치할 차례입니다. 해당 작업은 master 에서만 실행합니다.</p>
<pre><code class="line-numbers">kubeadm init

그럼 설치가 진행되고 마지막에 다음과 비슷한 로그가 출력됩니다.
Your Kubernetes master has initialized successfully!
</code></pre>
<p>마스터 노드가 활성화 되면 아래의 로그가 출력됩니다.</p>
<pre><code class="line-numbers">To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of machines by running the following on each node
as root:

  kubeadm join 10.146.0.25:6443 --token yuaea3.d7m8hkpvazrbv5yw --discovery-token-ca-cert-hash sha256:c6a7121c5d5207179f67d913fa654441137f76027ad0f4e23724f0202b280eec
</code></pre>
<p>여기서 일반 사용자가 kubectl 을 사용할 수 있도록 로그 중간에 있는 명령어를 복사해서 실행합니다.</p>
<pre><code class="line-numbers">mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
</code></pre>
<ul>
<li>인증서 셋팅하기</li>
</ul>
<p>접속하는 터미널의 인증서를 셋팅하는 과정으로 일반유저냐 Root계정이냐에 따라 설정이 다르므로 주의합니다.<br />
여기서는 Root유저로 설정했기 때문에 아래 명령어를 수행합니다.</p>
<pre><code># export KUBECONFIG=/etc/kubernetes/admin.conf</code></pre>
<ul>
<li>Pod network add-on 설치하기</li>
</ul>
<p>Pod 은 실제로 여러 노드에 걸쳐 배포되는데, Pod 끼리는 하나의 네트워크에 있는 것처럼 통신할 수 있습니다. 이를 오버레이 네트워크(Overlay Network)라고 합니다.<br />
Master 노드에서 다음과 같이 설치합니다.</p>
<pre><code class="line-numbers">kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
</code></pre>
<ul>
<li>워커 노드 클러스터링</li>
</ul>
<p>맨 마지막 라인의 명령어는 워커 노드를 해당 클러스터에 추가하는 명령어입니다. 해당 명령어를 복사해서 worker-1 노드에서 수행합니다.</p>
<pre><code class="line-numbers">kubeadm join 10.146.0.25:6443 --token yuaea3.d7m8hkpvazrbv5yw --discovery-token-ca-cert-hash sha256:c6a7121c5d5207179f67d913fa654441137f76027ad0f4e23724f0202b280eec
</code></pre>
<p>만약 해당 커맨드를 복사해놓지 않고 지워진 경우에는 다음과 같이 토큰을 확인할 수 있습니다.</p>
<pre><code class="line-numbers">kubeadm token list
</code></pre>
<p>해당 토큰은 24시간 동안만 사용할 수 있습니다. 새 토큰이 필요한 경우는 다음 명령어를 실행하면 됩니다</p>
<pre><code class="line-numbers">kubeadm token create
</code></pre>
<h2>3. 쿠버네티스 확인</h2>
<p>쿠버네티스 설치가 완료되면 다음의 명령으로 확인한다.</p>
<p>CNI를 설치하면 CoreDNS Pod 이 정상적으로 동작하게 됩니다.<br />
다음 명령어로 각 노드와 상태를 확인할 수 있습니다. 처음엔 상태가 NotReady 라고 나올 수 있지만 잠시 기다리면 모두 Ready 상태가 됩니다.</p>
<pre><code class="line-numbers">kubectl get no
NAME       STATUS   ROLES    AGE     VERSION
master     Ready    master   6m44s   v1.13.3
worker-1   Ready    <none>   5m20s   v1.13.3
worker-2   Ready    <none>   5m19s   v1.13.3
</code></pre>
<p><code>설치 확인하기</code><br />
다음 명령어로 쿠버네티스의 구성 요소가 모두 동작하는 것을 확인할 수 있습니다.</p>
<pre><code class="line-numbers">kubectl get componentstatuses
NAME                 STATUS    MESSAGE              ERROR
scheduler            Healthy   ok                   
controller-manager   Healthy   ok                   
etcd-0               Healthy   {"health": "true"}
</code></pre>
<h2>4. (예제) 간단한 POD 구성해보기</h2>
<p>먼저 간단한 Pod 을 배포해서 동작을 확인해봅시다. 다음과 같은 pod-test.yaml 파일을 생성합니다.</p>
<ul>
<li>deployment.yml</li>
</ul>
<pre><code class="line-numbers">apiVersion: apps/v1beta1
kind: Deployment
metadata:
  # Deployment 객체의 Unique한 명칭
  name: deployment-example
spec:
  # Deployment label selector for pod
  selector:
    matchLabels:
      app: nginx
  # 2 Pods should exist at all times.
  replicas: 2
  template:
    metadata:
      labels:
        # Pod의 라벨
        app: nginx
    spec:
      containers:
      - name: nginx
        # Run this image
        image: nginx:1.10
</code></pre>
<ul>
<li>service.yml</li>
</ul>
<pre><code class="line-numbers">apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  labels:
    run: nginx-svc
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 80
    protocol: TCP
  selector:
    app: nginx
</code></pre>
<p><code>deployment</code>와 <code>service</code>는 추후에 알아보겠습니다. 구성도는 아래와 같습니다.<br />
우선 위에 보시는것처럼 deployment안에 Pod을 배포하기 위한 내용들을 기입했습니다.</p>
<p>아래의 spec대로 2개의 replica를 생성하기 떄문에 pod은 아래보시는것처럼 생성됩니다 .</p>
<pre><code class="line-numbers">      containers:
      - name: nginx
        # Run this image
        image: nginx:1.10
</code></pre>
<p><code>service</code>는 아래 보시는것처럼 기존의 로드밸런스의 기능을 하는데, 그 타입이 3종류(ClusterIP, noteType, DNS)가 있습니다. 이는 추후에 알아보도록 하겠습니다.</p>
<p>8080포트로 접속이 되면, target (nginx)의 pod으로 80포트로 분산하겠다라는 내용의 서비스 입니다.</p>
<pre><code class="line-numbers">  ports:
  - port: 8080
    targetPort: 80
    protocol: TCP
  selector:
    app: nginx
</code></pre>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/K8S_exam.jpg?w=1200&#038;ssl=1" alt="Kubernetes 쿠버네티스 설치와 사용법 설명 이미지 2" /></p>
<h2>5. 마치며</h2>
<p>이번 포스트에서는 기존의 docker기반으로 올렸던 container들을 손쉽게 관리하기위한 cluster 도구에 대해서 알아봤습니다. 쿠버네티스는 오케스트레이션의 대표적인 도구이고, 예제에서 보시는것처럼 nginx 를 손쉽게 서비스에 붙여서 구성을 할 수 잇었습니다.</p>
<p>이번에는 개략적인 내용에 대해서 알았다면, 다음시간에는 쿠버네티스에서 사용하는 용어들에 대해서 하나씩 알아보는 시간을 갖도록 하겠습니다.</p>
<p><a href="http://blog.wonizz.com" title="워니즈 블로그">워니즈 블로그</a><br />
<a href="http://github.com/wonizz" title="워니즈 깃헙" target="_blank" rel="noopener">워니즈 깃헙</a></p>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/08/16/kubenetes-install-guide/">[Kubernetes] 쿠버네티스 설치와 사용법</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.wonizz.com/2019/08/16/kubenetes-install-guide/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">742</post-id>	</item>
		<item>
		<title>[Docker] Compose 구성과 사용법</title>
		<link>https://blog.wonizz.com/2019/08/13/docker-compose/</link>
					<comments>https://blog.wonizz.com/2019/08/13/docker-compose/#respond</comments>
		
		<dc:creator><![CDATA[워니]]></dc:creator>
		<pubDate>Tue, 13 Aug 2019 02:37:51 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[도커]]></category>
		<guid isPermaLink="false">http://blog.wonizz.tk/?p=731</guid>

					<description><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
<p>안녕하세요? 정리하는 개발자 워니즈입니다. 오늘은 docker의 compose구성법에 대해서 정리를 해보려고 합니다. 만약 여러분이 앱컨테이너와 데이터베이스 컨테이너의 실행 순서를 지켜서 실행해야한다고 생각해보세요. 반드시 데이터베이스 컨테이너를 실행한 다음에 앱 컨테이너를 실행해야 합니다. 그렇지 않으면 앱 컨테이너에서 데이터베이스 컨테이너를 찾을 수 없기 때문이죠. 깜박하고 앱 컨테이너부터 실행했다면? 종료하고 데이터베이스 컨테이너 실행하고, 다시 앱 컨테이너를 실행하는 불편함이 있죠. 도커&#8230;&#160;</p>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/08/13/docker-compose/">[Docker] Compose 구성과 사용법</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
안녕하세요? 정리하는 개발자 워니즈입니다. 오늘은 docker의 compose구성법에 대해서 정리를 해보려고 합니다.
 만약 여러분이 앱컨테이너와 데이터베이스 컨테이너의 실행 순서를 지켜서 실행해야한다고 생각해보세요. 반드시 데이터베이스 컨테이너를 실행한 다음에 앱 컨테이너를 실행해야 합니다. 그렇지 않으면 앱 컨테이너에서 데이터베이스 컨테이너를 찾을 수 없기 때문이죠. 깜박하고 앱 컨테이너부터 실행했다면? 종료하고 데이터베이스 컨테이너 실행하고, 다시 앱 컨테이너를 실행하는 불편함이 있죠.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/DC_main.jpg?w=1200&#038;ssl=1" alt="Docker Compose 구성과 사용법 설명 이미지 1" />

도커 컴포즈를 사용하면 컨테이너 실행에 필요한 옵션을 docker-compose.yml이라는 파일에 적어둘 수 있고, 컨테이너 간 실행 순서나 의존성도 관리할 수 있습니다.

<h2>1. docker-compose.yml 파일</h2>

docker-compose.yml은 장황한 도커 실행 옵션을 미리 적어둔 문서라고 볼 수 있습니다. 프로젝트 루트에 파일을 만들고, 다음 내용을 붙여 넣습니다.

<pre><code class="line-numbers">version: '3'

services:
  db:
    image: postgres
    volumes:
      - ./docker/data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=sampledb
      - POSTGRES_USER=sampleuser
      - POSTGRES_PASSWORD=samplesecret
      - POSTGRES_INITDB_ARGS=--encoding=UTF-8

  django:
    build:
      context: .
      dockerfile: ./compose/django/Dockerfile-dev
    environment:
      - DJANGO_DEBUG=True
      - DJANGO_DB_HOST=db
      - DJANGO_DB_PORT=5432
      - DJANGO_DB_NAME=sampledb
      - DJANGO_DB_USERNAME=sampleuser
      - DJANGO_DB_PASSWORD=samplesecret
      - DJANGO_SECRET_KEY=dev_secret_key
    ports:
      - "8000:8000"
    command: 
      - python manage.py runserver 0:8000
    volumes:
      - ./:/app/
</code></pre>

이제 한줄씩 확인해보면서 정리 하도록 해보겠습니다.

<ol>
<li>version

<pre><code class="line-numbers">version: '3'
</code></pre>

docker-compose.yml 파일의 첫 줄에는 파일 규격 버전을 적습니다. 파일의 규격에 따라 지원하는 옵션이 달라지는데, “3”이라만 적으면 3으로 시작하는 최신 버전을 사용한다는 의미입니다. (파일 규격 버전에 따른 자세한 내용은 compose 파일의 버전과 호환성을 안내한 공식 문서를 참고하세요.)</p></li>
<li>services

<pre><code class="line-numbers">services:
</code></pre>

이 항목 밑에 실행하려는 컨테이너들을 정의합니다. 컴포즈에서는 컨테이너 대신 서비스라는 개념을 사용합니다.</p></li>
<li>db

<pre><code class="line-numbers">services:
 db:
</code></pre>

postgres 서비스의 이름을 db로 정하였습니다.</p></li>
<li>image

<pre><code class="line-numbers">services:
 db:
   image: postgres
</code></pre>

db 서비스에서 사용할 도커 이미지를 적습니다. 여기서는 dockerhub의 공식 postgres 이미지를 사용하였습니다.</p></li>
<li>volumes

<pre><code class="line-numbers">services:
 db:
   volumes:
     - ./docker/data:/var/lib/postgresql/data
</code></pre>

docker run으로 db 컨테이너를 실행할 때 &#8211;volume 옵션을 사용하여 데이터베이스의 데이터를 로컬 컴퓨터에 저장했던 부분과 같습니다. 다만 docker-compose.yml의 volumes에는 상대 경로를 지정할 수 있어서 편리합니다.

docker run으로 db 컨테이너를 실행할 때와 마찬가지로, 프로젝트 루트 아래의 docker/data 디렉터리에 데이터를 저장하기로 했습니다.</p></li>
<li>environment

<pre><code class="line-numbers">services:
 db:
   environment:
     - POSTGRES_DB=sampledb
     - POSTGRES_USER=sampleuser
     - POSTGRES_PASSWORD=samplesecret
     - POSTGRES_INITDB_ARGS=--encoding=UTF-8
</code></pre>

docker run 명령어의 -e 옵션에 적었던 내용들입니다. 마지막의 POSTGRES_INITDB_ARGS 부분이 추가되었는데, 데이터베이스 서버의 인코딩을 UTF-8로 설정하기 위함입니다.</p></li>
<li>django

<pre><code class="line-numbers">services:
 django:
</code></pre>

앱 서비스의 이름은 django로 지정하였습니다.</p></li>
<li>build

<pre><code class="line-numbers">services:
 django:
   build:
     context: .
     dockerfile: ./compose/django/Dockerfile-dev
</code></pre>

db 서비스와 달리 앱 서비스는 특정 이미지 대신 build 옵션을 추가합니다.

context는 docker build 명령을 실행할 디렉터리 경로라고 보시면 됩니다.

dockerfile에는 ‘개발용’ 도커 이미지를 빌드하는 데 사용할 Dockerfile을 지정하면 됩니다. Dockerfile-dev 파일에서는 (운영용 Dockerfile과는 달리) 소스코드를 컨테이너에 넣지 않습니다.</p></li>
<li>ports

<pre><code class="line-numbers">services:
 django:
   ports:
     - "8000:8000"
</code></pre>

docker run 명령어의 -p 옵션에 해당하는 부분입니다.</p></li>
<li><p>command

<pre><code class="line-numbers">services:
  django:
    command:
      - python manage.py runserver 0:8000
</code></pre>

docker run으로 앱 컨테이너를 실행할 때 가장 마지막에 적었던 명령어 부분입니다.</p></li>
</ol>

<h2>2. 도커 컴포즈의 주요 명령어</h2>

<ul>
<li>up -d</li>
</ul>

<pre><code class="line-numbers">docker-compose.yml 파일의 내용에 따라 이미지를 빌드하고 서비스를 실행합니다. 자세한 진행 과정은 다음과 같습니다.
</code></pre>

<p>서비스를 띄울 네트워크 설정
필요한 볼륨 생성(혹은 이미 존재하는 볼륨과 연결)
필요한 이미지 풀(pull)
필요한 이미지 빌드(build)
서비스 의존성에 따라 서비스 실행
up 명령에 사용할 수 있는 몇 가지 옵션도 존재합니다.

-d: 서비스 실행 후 콘솔로 빠져나옵니다. (docker run에서의 -d와 같습니다.)
&#8211;force-recreate: 컨테이너를 지우고 새로 만듭니다.
&#8211;build: 서비스 시작 전 이미지를 새로 만듭니다.

<ul>
<li>ps</li>
</ul>

현재 환경에서 실행 중인 각 서비스의 상태를 보여줍니다.

<pre><code class="line-numbers">$ docker-compose ps
        Name                       Command               State           Ports
--------------------------------------------------------------------------------
djangosample_db_1       /docker-entrypoint.sh postgres   Up      5432/tcp
djangosample_django_1   /bash -c python manage.py        Up      0.0.0.0:8000->8000/tcp
</code></pre>

<ul>
<li>stop, start</li>
</ul>

서비스를 멈추거나, 멈춰 있는 서비스를 시작합니다.

<pre><code class="line-numbers">$ docker-compose stop
Stopping djangosample_django_1 ...
Stopping djangosample_db_1 ...

$ docker-compose start
Starting db ... done
Starting django ... done
</code></pre>

<ul>
<li>down</li>
</ul>

서비스를 지웁니다. 컨테이너와 네트워크를 삭제하며, 옵션에 따라 볼륨도 지웁니다.

<pre><code class="line-numbers">$ docker-compose down --volume
Removing myproject_django_1 ... done
Removing myproject_db_1 ... done
Removing network djangosample_default
Removing volume django_sample_db_dev
</code></pre>

&#8211;volume: 볼륨까지 삭제합니다.

<ul>
<li>exec</li>
</ul>

실행 중인 컨테이너에서 명령어를 실행합니다. 자동화된 마이그레이션용 파일 생성이나 유닛 테스트, lint 등을 실행할 때 사용합니다.*

<ul>
<li>비슷한 명령으로 run이 존재합니다. run은 새 컨테이너를 만들어서 명령어를 실행합니다. docker run과 마찬가지로 &#8211;rm 옵션을 추가하지 않으면, 컨테이너가 종료된 후에도 삭제되지 않습니다. (이런 이유 때문에 개인적으로는 exec를 선호하지만, 컨테이너에서 추천하는 방식은 사실 run입니다.)</li>
</ul>

<pre><code class="line-numbers">$ docker-compose exec django ./manage.py makemigrations
...
$ docker-compose exec node npm run test
> expresssample@0.1.0 test /www/service
> mocha $(find test -name '*.spec.js')
...
</code></pre>

<ul>
<li>logs</li>
</ul>

서비스의 로그를 확인할 수 있습니다. logs 뒤에 서비스 이름을 적지 않으면 도커 컴포즈가 관리하는 모든 서비스의 로그를 함께 보여줍니다.

<pre><code class="line-numbers">$ docker-compose logs django
Attaching to djangosample_django_1
django_1     | System check identified no issues (0 silenced).
django_1     | February 13, 2017 - 16:32:28
django_1     | Django version 1.10.4, using settings 'djangosample.settings'
django_1     | Starting development server at http://0.0.0.0:8000/
django_1     | Quit the server with CONTROL-C.
</code></pre>

-f: 지금까지 쌓인 로그를 다 보여준 후에도 셸로 빠져나오지 않고, 로그가 쌓일 때마다 계속해서 출력합니다.

<h2>3. 예시</h2>

필자에게 업무중 주어진 미션이 각종 tool 들을 업그레이드 버전으로 설치하는 것이였다. 그런데 리눅스를 다뤄보신 분들은 알겠지만, 업그레이드라는게 yum 으로 쉽사리 설치가 되면 좋겠지만 각종 설정 파일들부터 복원 계획도 다 갖고 있어야 한다.

필자의 프로젝트에서는 grafana, zabbix, rundeck, kibana, eleasticsearch 등 다양한 도구들을 활용하고 있는데, 업그레이드를 하면서 지속적으로 기존 시스템에 영향을 주지 않는 범위내에서 해보고 싶었고, docker가 제격이라고 생각하게 되었다.

다음의 시나리오대로 grafana를 업그레이드 해봤습니다.

<ol>
<li>기존 파일 백업

<pre><code class="line-numbers">- /var/lib/grafana 경로에서 데이터 백업
cp -r grafana grafana_bak 

그라파나의 데이터베이스 경로
</code></pre></li>
<li>도커 컨테이너 실행

공식 문서에 보면, 다음과 같이 도커를 실행하라고 명시되어있다.

<pre><code class="line-numbers">$ docker run \
 -d \
 -p 3000:3000 \
 --name=grafana \
 -e "GF_SERVER_ROOT_URL=http://grafana.server.name" \
 -e "GF_SECURITY_ADMIN_PASSWORD=secret" \
 grafana/grafana
</code></pre>

위의 명령어를 보시면 알겠지만,

-d : 데몬(백그라운드) 실행

-p : 포트 포워딩

&#8211;name : 컨테이너 네임 명시

-e : 환경 변수 : 그라파나 configure에 명시되어있어서 없어도도.ㅁ

grafana/grafana : 이미지 명시 (최신 이미지 가져옴) -> grafana/grafana:5.1.0 특정 버전 명시가능

필요한 플러그인 업데이트

*실제로 설치하고 난뒤, Zabbix plugin for Grafana 가 에러가 발생하여, 컨테이너 내부에서 업데이트를 하였습니다

<pre><code class="line-numbers">grafana-cli plugins install <plugin-id>
</code></pre></li>
<li>컴포즈 구성으로 변경

<pre><code class="line-numbers">version: "2.1"
services:
 grafana:
     image: grafana
     restart: always
     container_name: grafana
     volumes:
       - "/var/lib/grafana:/var/lib/grafana"
     expose:
       - 3000
     ports:
       - "3000:3000"
</code></pre>

위의 docker 명령어를 명시해 놓은 compose 파일로 간단하게 실행이 가능합니다.

</li>
<li>

컨테이너 실행

<pre><code class="line-numbers">docker-compose up -d
</code></pre>

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/DC_example.jpg?w=1200&#038;ssl=1" alt="Docker Compose 구성과 사용법 설명 이미지 2" />

</li>
</ol>

<a href="http://blog.wonizz.com" title="블로그 워니즈">블로그 워니즈</a>
<a href="http://github.com/wonizz" title="워니즈 블로그" target="_blank" rel="noopener">워니즈 블로그</a>
<h2 class="wp-block-heading">함께 보면 좋은 글</h2>
<ul class="wp-block-list"><li><a href="https://blog.wonizz.com/2019/07/31/docker-dockerfile/">[Docker] Dockerfile 의 이해</a></li><li><a href="https://blog.wonizz.com/2019/07/29/docker-volume/">[Docker] Volume 의 관리</a></li><li><a href="https://blog.wonizz.com/2019/07/27/docker-network/">[Docker] 네트워크의 이해</a></li><li><a href="https://blog.wonizz.com/2019/08/08/ansible-role-include/">[Ansible] 플레이북 Role 과 Include</a></li></ul>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/08/13/docker-compose/">[Docker] Compose 구성과 사용법</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.wonizz.com/2019/08/13/docker-compose/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">731</post-id>	</item>
		<item>
		<title>[Ansible] 플레이북 Role 과 Include</title>
		<link>https://blog.wonizz.com/2019/08/08/ansible-role-include/</link>
					<comments>https://blog.wonizz.com/2019/08/08/ansible-role-include/#respond</comments>
		
		<dc:creator><![CDATA[워니]]></dc:creator>
		<pubDate>Thu, 08 Aug 2019 05:49:51 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[공부]]></category>
		<category><![CDATA[도커]]></category>
		<guid isPermaLink="false">http://blog.wonizz.tk/?p=723</guid>

					<description><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
<p>안녕하세요? 정리하는 개발자 워니즈입니다. 이번시간에는 Ansible 의 플레북에 대한 이야기를 해보려고 합니다. 필자가 속한 프로젝트에서는 Ansible을 주로 다수의 서버의 configuration 을 수정할 때 사용하고 있습니다. 즉, 1개의 master 파일을 수정하고 각 서버의 경로에 해당 파일로 copy 해주는 단순한 구조입니다. 필자가 있는 프로젝트에서는 다음과 같이 사용합니다 . nginx conf 파일 변경 nginx map 파일 변경 nginx&#8230;&#160;</p>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/08/08/ansible-role-include/">[Ansible] 플레이북 Role 과 Include</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
안녕하세요? 정리하는 개발자 워니즈입니다. 이번시간에는 <code>Ansible</code> 의 플레북에 대한 이야기를 해보려고 합니다. 필자가 속한 프로젝트에서는 Ansible을 주로 다수의 서버의 configuration 을 수정할 때 사용하고 있습니다. 즉, 1개의 master 파일을 수정하고 각 서버의 경로에 해당 파일로 copy 해주는 단순한 구조입니다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/ANSIBLE_playbook.png?w=1200&#038;ssl=1" alt="ansible playbook" />

필자가 있는 프로젝트에서는 다음과 같이 사용합니다 .

<ul>
<li>nginx conf 파일 변경</li>
<li>nginx map 파일 변경</li>
<li>nginx location 파일 변경</li>
</ul>

다음시간에 <code>nginx</code> conf 구조에 대해서 설명을 하겠지만, 우선 ansible의 가장 효과적인 부분이 다수의 host에서 작업이 가능한 것입니다.

플레이북을 매우 큰 하나의 파일로 작성하는 것도 가능하지만 (초기에 플레이북을 배우면서는 이렇게 하기도 합니다) 점차 플레이북을 재사용하거나 계층적으로 관리할 필요도 생깁니다.

<h2>1. Ansible include</h2>

만약 플레이북의 플레이에 있는 일련의 태스크를 재사용한다고 가정해봅니다. <strong><em>include</em></strong> 를 이용하여 이 작업을 하면 됩니다. 가져온 태스크 목록은 특정 역할(role)을 수행하기에 알맞습니다. 다시한번 강조하면 플레이북은 관리 대상 시스템 그룹에 다양한 역할을 매핑하는 작업입니다.

<pre><code class="line-numbers">---
# possibly saved as tasks/foo.yml

- name: placeholder foo
  command: /bin/foo

- name: placeholder bar
  command: /bin/bar
</code></pre>

<pre><code class="line-numbers">tasks:

  - include: tasks/foo.yml
</code></pre>

분명 위와 아래는 확연히 달라집니다. 같은 내용이더라도, 파일을 <code>include</code>하는 구조가 훨씬 간단해 보입니다.

include 할 때 변수도 포함해서 가져올 수 있습니다. (<em>parameterized include</em> 라고 합니다)

<pre><code class="line-numbers">tasks:
  - include: wordpress.yml wp_user=timmy
  - include: wordpress.yml wp_user=alice
  - include: wordpress.yml wp_user=bob
</code></pre>

버전 1.0 상위부터는 아래와 같이 key, value pair로도 지정이 가능합니다.

<pre><code class="line-numbers">tasks:

  - include: wordpress.yml
    vars:
        wp_user: timmy
        ssh_keys:
          - keys/one.txt
          - keys/two.txt
</code></pre>

<strong><em>include</em></strong>에 작접 패러미터를 전달하던 아니면 <code>vars</code>를 이용하던 상관없습니다.
include 되는 파일에서는

<pre><code class="line-numbers">{{ wp_user }}
</code></pre>

여러개의 하위 플레이북도 <code>include</code> 가 가능합니다.

<pre><code class="line-numbers">- name: this is a play at the top level of a file
  hosts: all
  remote_user: root

  tasks:

  - name: say hi
    tags: foo
    shell: echo "hi..."

- include: load_balancers.yml
- include: webservers.yml
- include: dbservers.yml
</code></pre>

<h2>2. Ansible Role</h2>

버전 1.2 이후

태스크와 핸들러에 관하여 알았으므로 이제는 플레이북을 어떻게 잘 구성하는가를 알아낼 차례입니다. Role을 이용 하면 됩니다. Role은 파일 구조에 따라 vars_files, tasks 와 핸들러 등을 자동으로 로딩하는 것입니다.

처음에 필자는 <code>Role</code>이라는 것 자체가 계정과 역할 이런것일줄 알았는데, 말그대로 어떤 업무 수행단위를 하는지를 Component화 해서 재사용할 수 있도록 하는것으로 보면 될 것 같습니다.

다음과 같은 프로젝트 구조가 되어 있다고 합시다.

<pre><code class="line-numbers">site.yml
webservers.yml
fooservers.yml
roles/
   common/
     files/
     templates/
     tasks/
     handlers/
     vars/
     defaults/
     meta/
   webservers/
     files/
     templates/
     tasks/
     handlers/
     vars/
     defaults/
     meta/
</code></pre>

플레이북에는 다음과 같이 사용합니다.

<pre><code class="line-numbers">---
- hosts: webservers
  roles:
     - common
     - webservers
</code></pre>

다음과 같이 role <code>x</code> 에 대하여 작업이 진행됩니다.

<ul>
<li>만약 <strong>roles/x/tasks/main.yml</strong> 이 존재하면, 그곳에 있는 태스크 들이 플레이에 추가됩니다</li>
<li>만약 <strong>roles/x/handlers/main.yml</strong> 이 존재하면, 그곳에 있는 핸들러 들이 플레이에 추가됩니다</li>
<li>만약 <strong>roles/x/vars/main.yml</strong> 이 존재하면, 그곳에 있는 변수 들이 플레이에 추가됩니다</li>
<li>만약 <strong>roles/x/defaults/main.yml</strong> 이 존재하면, 그곳에 있는 변수 들이 플레이에 추가됩니다</li>
<li>만약 <strong>roles/x/meta/main.yml</strong> 이 존재하면, 그곳에 있는 role 의존성이 role 목록에 추가됩니다 (role 의존성은 아래에 따로 설명합니다)</li>
<li>Role에 있는 다른 어떤 copy, script, template 또는 include task 들은 <strong>role/x/{files,templates,tasks}/</strong> 에 있는 것을 참조합니다.</li>
</ul>

버전 1.4 이후에는 role을 찾기위한 <code>roles_path</code> 설정 변수를 사용할 수 있습니다.

만약 해당 파일이 존재하지 않으면 해당 내용은 무시됩니다. 예를 들어 role을 위한 <strong>vars/</strong> 하위 디렉터리는 없을 수도 있습니다.

<ul>
<li>파라미터 방식</li>
</ul>

<pre><code class="line-numbers">---
- hosts: webservers
  roles:
    - common
    - { role: foo_app_instance, dir: '/opt/a',  app_port: 5000 }
    - { role: foo_app_instance, dir: '/opt/b',  app_port: 5001 }
</code></pre>

<ul>
<li>조건부 방식</li>
</ul>

<pre><code class="line-numbers">---
- hosts: webservers
  roles:
    - { role: some_role, when: "ansible_os_family == 'RedHat'" }
</code></pre>

<ul>
<li>태그방식</li>
</ul>

<pre><code class="line-numbers">---
- hosts: webservers
  roles:
    - { role: foo, tags: ["bar", "baz"] }
</code></pre>

role의 태스크에 있는 이런 tag는 role 안에 단순 정의된 tag를 우선합니다. 만약 만약 특정 role에 있는 여러 task를 부분적으로 사용할 필요가 생긴다면 해당 role을 더 작은 단위로 나눌 필요가 있습니다.

<ul>
<li>순서 지정</li>
</ul>

<pre><code class="line-numbers">---

- hosts: webservers

  pre_tasks:
    - shell: echo 'hello'

  roles:
    - { role: some_role }

  tasks:
    - shell: echo 'still busy'

  post_tasks:
    - shell: echo 'goodbye'
</code></pre>

<h2>3. Ansible Role 예제 분석</h2>

<code>ansible galaxy</code>라는 것을 알게 되어, 처음으로 <code>docker</code> 설치를 한번 해보기 위해서 예제를 다운받았습니다.

<ol>
<li>https://galaxy.ansible.com/geerlingguy/docker 접속</li>
<li>ansible 이 설치된 서버에서 다음을 실행</li>
</ol>

<pre><code class="line-numbers">$ cd /etc/ansible/
$ ansible-galaxy install geerlingguy.docker
</code></pre>

<ol start="3">
<li>roles 폴더 확인</li>
</ol>

<pre><code class="line-numbers">$ cd /etc/ansible/roles
</code></pre>

<pre><code class="line-numbers">defaults/main.yml
handlers/main.yml
LICENSE
meta/main.yml
molecule
README.md
tasks/main.yml
     /docker-1809-shim.yml
     /docker-compose.yml
     /docker-users.yml
     /setup-Debian.yml
     /setup-RedHat.yml
templates/override.conf.j2
</code></pre>

<ol start="4">
<li>실행</li>
</ol>

/etc/ansible 경로에 playbook_docker_test.yml 파일을 생성한뒤, playbook을 실행합니다.

<pre><code class="line-numbers">ansible-playbook playbook_docker_test.yml
</code></pre>

<pre><code class="line-numbers">- hosts: test
  roles:
    - geerlingguy.docker
</code></pre>

<ol start="5">
<li>실행결과 해석</li>
</ol>

<pre><code class="line-numbers">PLAY [test] ************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************************************************************************************************************
ok: [https_ids_a01]

TASK [geerlingguy.docker : include_tasks] *****************************************************************************************************************************************************************************************
included: /etc/ansible/roles/geerlingguy.docker/tasks/setup-RedHat.yml for https_ids_a01

TASK [geerlingguy.docker : Ensure old versions of Docker are not installed.] ******************************************************************************************************************************************************
ok: [https_ids_a01]

TASK [geerlingguy.docker : Add Docker GPG key.] ***********************************************************************************************************************************************************************************
ok: [https_ids_a01]

TASK [geerlingguy.docker : Add Docker repository.] ********************************************************************************************************************************************************************************
ok: [https_ids_a01]

TASK [geerlingguy.docker : Configure Docker Edge repo.] ***************************************************************************************************************************************************************************
 [WARNING]: The value 0 (type int) in a string field was converted to u'0' (type string). If this does not look like what you expect, quote the entire value to ensure it does not change.

ok: [https_ids_a01]

TASK [geerlingguy.docker : Configure Docker Test repo.] ***************************************************************************************************************************************************************************
ok: [https_ids_a01]

TASK [geerlingguy.docker : include_tasks] *****************************************************************************************************************************************************************************************
skipping: [https_ids_a01]

TASK [geerlingguy.docker : install the container-selinux rpm from a remote repo] **************************************************************************************************************************************************
ok: [https_ids_a01]

TASK [geerlingguy.docker : Install Docker.] ***************************************************************************************************************************************************************************************
changed: [https_ids_a01]

TASK [geerlingguy.docker : Ensure containerd service dir exists.] **************************************************************************************************************************************************************************
ok: [https_ids_a01]

TASK [geerlingguy.docker : Add shim to ensure Docker can start in all environments.] *******************************************************************************************************************************************************
ok: [https_ids_a01]

TASK [geerlingguy.docker : Reload systemd daemon if template is changed.] ******************************************************************************************************************************************************************
skipping: [https_ids_a01]

TASK [geerlingguy.docker : Ensure Docker is started and enabled at boot.] ******************************************************************************************************************************************************************
changed: [https_ids_a01]

RUNNING HANDLER [geerlingguy.docker : restart docker] **************************************************************************************************************************************************************************************
changed: [https_ids_a01]

TASK [geerlingguy.docker : include_tasks] **************************************************************************************************************************************************************************************************
included: /etc/ansible/roles/geerlingguy.docker/tasks/docker-compose.yml for https_ids_a01

TASK [geerlingguy.docker : Check current docker-compose version.] **************************************************************************************************************************************************************************
ok: [https_ids_a01]

TASK [geerlingguy.docker : Delete existing docker-compose version if it's different.] ******************************************************************************************************************************************************
skipping: [https_ids_a01]

TASK [geerlingguy.docker : Install Docker Compose (if configured).] ************************************************************************************************************************************************************************
ok: [https_ids_a01]

TASK [geerlingguy.docker : include_tasks] **************************************************************************************************************************************************************************************************
[DEPRECATION WARNING]: evaluating [] as a bare variable, this behaviour will go away and you might need to add |bool to the expression in the future. Also see CONDITIONAL_BARE_VARS configuration toggle.. This feature will be removed in
 version 2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
skipping: [https_ids_a01]

PLAY RECAP *********************************************************************************************************************************************************************************************************************************
https_ids_a01              : ok=16   changed=3    unreachable=0    failed=0    skipped=4    rescued=0    ignored=0   
</code></pre>

제일 먼저, 위의 플레이북 실행 결과를 보면, <code>task/main.yml</code>이 실행 됩니다.

<ul>
<li>setup-RedHat.yml

<ul>
<li>도커 설치</li>
</ul></li>
<li>docker-1809-shim.yml

<ul>
<li>도커 정상시작 체크</li>
<li>도커 방화벽 충돌체크</li>
</ul></li>
<li>docker-compose.yml</li>
<li>docker-users.yml</li>
</ul>

Task의 구조는 위와 같고, 각 yml 파일들이 <code>include</code>되면서 수행이 됩니다.

<h2>4. 필자 Ansible 사용예시</h2>

포스트 서두에 말씀드렸듯이, 필자가 사용하는 방법은 nginx configuration 파일들에 대해서 변경해주고 재시작해주는 방식으로 사용하고 있습니다. 여기서 변경할때는 <code>copy</code>를 하게 되는데 nginx의 멱등성에 의거하여 변경점이 없으면, 업데이트를 안하게 됩니다.

<ol>
<li>playbook_nginx_conf.yml</li>
</ol>

<pre><code class="line-numbers">- hosts: "{{ server }}"
  remote_user: idsuser  
  tasks:
  - name: Change Nginx Config file
    become: yes
    become_method: sudo
    template:
      src: /etc/ansible/config/{{server}}/nginx.conf
      dest: /etc/nginx/nginx.conf

  - name: Validate Config file
    become: yes
    become_method: sudo
    command: "nginx -t"
    register: shell_result

  - debug:
      var: shell_result.stderr_lines
</code></pre>

따로 <code>role</code>관리를 안하고 상위에서 보듯이 하나의 playbook으로 작성했습니다.

<ul>
<li>config 파일 변경</li>
<li>config 파일 이상유무 테스트</li>
</ul>

<ol start="2">
<li>playbook_nginx_restart.yml</li>
</ol>

<pre><code class="line-numbers">- hosts: idsqa_a01
  remote_user: idsuser
  tasks:
  - name: Syntax Test  Nginx.conf
    become: yes
    become_method: sudo
    command: "nginx -t"
    register: shell_result

  - debug:
      var: shell_result.stderr_lines

  - name: Restart Nginx
    become: yes
    become_method: sudo
    service: name=nginx state=restarted
    when: '"nginx: configuration file /etc/nginx/nginx.conf test is successful" in shell_result.stderr_lines'

  - name: Check Nginx Status
    become: yes
    become_method: sudo
    shell: service nginx status
    args:
      warn: false
    register: service_status

  - debug:
      var: service_status.stdout_lines

  - name: Check Process Nginx
    become: yes
    become_method: sudo
    shell: 'ps -ef | grep nginx'
    register: process_result

  - debug:
      var: process_result.stdout_lines

</code></pre>

<ul>
<li>config 파일 이상유무 테스트</li>
<li>nginx 재시작</li>
<li>nginx status 체크</li>
<li>nginx process 체크</li>
</ul>

두 개의 파일로 분할해 두었는데, <code>role</code> 로 <code>task</code>를 쪼개고 하나의 job으로 만드는 것도 좋을 것 같습니다.

<h2>5. 마치며..</h2>

오늘은 ansible의 <code>role</code>과 <code>include</code>에 대해서 알아봤습니다. ansible을 필자도 사용은 하지만, 아주 기초적인 수준으로 사용하고 있었다라는 것을 느꼈습니다. 이번기회에 <code>role</code>관리를 좀더 잘해보고, 특히 <code>ansible-galaxy</code>를 통해서 수준높은 <code>role</code> 관리에 대해서 학습을 좀 더 해보도록 하겠습니다.

다음 시간에는 ansible <code>jinja2</code> 에 대해서 알아보는 시간을 갖도록 하겠습니다.

<a href="http://blog.wonizz.com" title="워니즈 블로그">워니즈 블로그</a>
<a href="http://github.com/wonizz" title="워니즈 깃헙" target="_blank" rel="noopener">워니즈 깃헙</a>
<h2 class="wp-block-heading">함께 보면 좋은 글</h2>
<ul class="wp-block-list"><li><a href="https://blog.wonizz.com/2019/07/31/docker-dockerfile/">[Docker] Dockerfile 의 이해</a></li><li><a href="https://blog.wonizz.com/2019/07/29/docker-volume/">[Docker] Volume 의 관리</a></li><li><a href="https://blog.wonizz.com/2019/08/13/docker-compose/">[Docker] Compose 구성과 사용법</a></li><li><a href="https://blog.wonizz.com/2019/07/27/docker-network/">[Docker] 네트워크의 이해</a></li></ul>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/08/08/ansible-role-include/">[Ansible] 플레이북 Role 과 Include</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.wonizz.com/2019/08/08/ansible-role-include/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">723</post-id>	</item>
		<item>
		<title>[Docker] Jenkins 파이프라인 사용법</title>
		<link>https://blog.wonizz.com/2019/08/04/jenkins-pipeline/</link>
					<comments>https://blog.wonizz.com/2019/08/04/jenkins-pipeline/#respond</comments>
		
		<dc:creator><![CDATA[워니]]></dc:creator>
		<pubDate>Sun, 04 Aug 2019 13:18:33 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[도커]]></category>
		<guid isPermaLink="false">http://blog.wonizz.tk/?p=689</guid>

					<description><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
<p>안녕하세요? 정리하는 개발자 워니즈 입니다. 지난 시간까지 젠킨스 셋팅까지 배웠습니다. 이제 원하는 업무를 수행하도록 JOB을 생성해주면됩니다. Jenkins에서는 요즘 여러가지 JOB을 원하는 입맛대로 구성하여 사용할 수 있도록 젠킨스 파이프라인을 제공해주고 있습니다. 👍 Jenkins 도커로 실행하기(1/3) Jenkins 기본 셋업(Docker 내부에서 필요한 툴 설치)(2/3) Jenkins 파이프라인 사용법(3/3) 1. 젠킨스 파이프라인이란? A Jenkins pipeline is a suite of plugins&#8230;&#160;</p>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/08/04/jenkins-pipeline/">[Docker] Jenkins 파이프라인 사용법</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
<p>안녕하세요? 정리하는 개발자 워니즈 입니다. 지난 시간까지 젠킨스 셋팅까지 배웠습니다. 이제 원하는 업무를 수행하도록 JOB을 생성해주면됩니다. Jenkins에서는 요즘 여러가지 JOB을 원하는 입맛대로 구성하여 사용할 수 있도록 젠킨스 파이프라인을 제공해주고 있습니다. 👍</p>
<p><a href="https://blog.wonizz.com/2019/08/01/docker-jenkins/" title="Jenkins 도커로 실행하기(1/3)">Jenkins 도커로 실행하기(1/3)</a><br />
<a href="https://blog.wonizz.com/2019/08/03/docker-jenkins-basic-setup/" title="Jenkins 기본 셋업(Docker 내부에서 필요한 툴 설치)(2/3)">Jenkins 기본 셋업(Docker 내부에서 필요한 툴 설치)(2/3)</a><br />
<a href="https://blog.wonizz.com/2019/08/04/jenkins-pipeline/" title="Jenkins 파이프라인 사용법(3/3)">Jenkins 파이프라인 사용법(3/3)</a></p>
<h2>1. 젠킨스 파이프라인이란?</h2>
<blockquote><p>
  A Jenkins pipeline is a suite of plugins which supports implementing and integrating continuous delivery pipelines into Jenkins.
</p></blockquote>
<p>위에서 보는 것처럼, 젠킨스 파이프라인은 젠킨스의 파이프라인을 구성해줄 수 있는 파이프라인 플러그인을 말하는 것이고, 이 파이프라인으로부터 제킨스의 워크플로우를 구성할 수 있다.</p>
<p><img decoding="async" src="https://qph.fs.quoracdn.net/main-qimg-928f83effe3f46296ef857b098c1e2a6" alt="젠킨스 파이프라인 구성" /><br />
<a href="https://jenkins.io/doc/book/pipeline/syntax/" title="젠킨스 파이프라인 공식문서" target="_blank" rel="noopener">젠킨스 파이프라인 공식문서</a><br />
위의 예제에서 보듯이 워크플로우가 시작되면, 아래의 과정들로 진행됩니다.</p>
<ol>
<li>소스 pull</li>
<li>빌드</li>
<li>테스트</li>
<li>배포</li>
</ol>
<p>물론, 젠킨스의 다양한 플러그인을 이용해서 한개의 JOB에서 다른 JOB을 실행하게 하여 연결을 지을 수는 있지만, 한눈에 보기가 어렵습니다.</p>
<p>젠킨스의 파이프라인이란 연속적인 이벤트 혹은 Job의 그룹을 얘기합니다.<br />
즉, 본인이 만든 젠킨스 Job들을 순차적 혹은 병렬적으로 실행시키거나 특별하게 작성한 스크립트로 이벤트들을 연속적으로 실행시키는 등의 일을 지원하는 기능입니다.</p>
<h2>2. 젠킨스 파이프라인 타입</h2>
<p>젠킨슴 파이프라인의 타입은 2가지를 지원합니다.</p>
<ol>
<li>선언적 파이프라인</li>
<li>스크립트 파이프라인</li>
</ol>
<p>그런데 <a href="https://jenkins.io/doc/book/pipeline/syntax/" target="_blank" rel="noopener">파이프라인 문법 문서</a>를 보면 두가지 스타일에 대한 얘기가 있습니다. 처음에는 Scripted 방식이였고 후에 <a href="https://jenkins.io/blog/2017/02/03/declarative-pipeline-ga/" target="_blank" rel="noopener">Declarative 방식이 추가</a>된 것으로 보입니다.</p>
<p>필자는 젠킨스 공식 문서를 보고 스크립트를 작성했는데, 개인적으로는 선언적 방식이 훨씬 간단해보여서 이방식으로 예제를 작성했습니다.</p>
<ul>
<li>선언적 방식 예제</li>
</ul>
<pre><code class="line-numbers">pipeline {
    agent none
    stages{
        stage('Parallel Test') {
            parallel { 
                stage('Build-test-1') {
                    steps{ build 'Build-test-1' }
                }
                stage('Build-test-2') {
                    steps{ build 'Build-test-2' }
                }
                stage('Build-test-3') {
                    steps{ build 'Build-test-3' }
                }
            }
        }
        stage('Build-test-4') {
            steps{
                build 'Build-test-4'
            }
        }
    }
}
</code></pre>
<ul>
<li>스크립트 방식 예제</li>
</ul>
<pre><code class="line-numbers">node {
  stage('Parallel-test') {
      parallel 'Build-test-1' : {
          build job : 'Build-test-1'
      } , 'Build-test-2' : {
          build job : 'Build-test-2'
      } , 'Build-test-3' : {
          build job : 'Build-test-3'
      }
  }
  stage('Build-test-4') {
     build job : 'Build-test-4'
  }
}
</code></pre>
<p>Scripted 문법의 경우 Groovy로 빌드되기 때문에 일반적으로 파이프라인을 생성하는데 Declarative 보다 훨씬 <strong>유연한 방법</strong>입니다.<br />
반면, Declarative의 경우 <strong>Scripted보다 훨씬 더 간단하게 작성</strong>할 수 있는 방법입니다.<br />
대신 고정된 방식으로만 사용해야합니다.</p>
<p>중요한 점은 이 2가지 문법은 <strong>서로 호환되지 않습니다</strong>.</p>
<ul>
<li>
<ul>
<li>A password parameter, for example: <code>parameters { password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'A secret password') }</code></p>
</li>
</ul>
<pre><code class="line-numbers">Jenkinsfile (Declarative Pipeline)
pipeline {
  agent any
  parameters {
      string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?')

      text(name: 'BIOGRAPHY', defaultValue: '', description: 'Enter some information about the person')

      booleanParam(name: 'TOGGLE', defaultValue: true, description: 'Toggle this value')

      choice(name: 'CHOICE', choices: ['One', 'Two', 'Three'], description: 'Pick something')

      password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'Enter a password')
  }
  stages {
      stage('Example') {
          steps {
              echo "Hello ${params.PERSON}"

              echo "Biography: ${params.BIOGRAPHY}"

              echo "Toggle: ${params.TOGGLE}"

              echo "Choice: ${params.CHOICE}"

              echo "Password: ${params.PASSWORD}"
          }
      }
  }
}
</code></pre>
</li>
<li>triggers : cront, pollSCM, upstream 등 여러방식으로 트리거를 구성할 수 있다.<br />
ex. 새벽 3시마다 빌드하기</p>
<pre><code class="line-numbers">Jenkinsfile (Declarative Pipeline)
pipeline {
  agent any
  triggers {
      cron('H */4 * * 1-5')
  }
  stages {
      stage('Example') {
          steps {
              echo 'Hello World'
          }
      }
  }
}
</code></pre>
</li>
</ul>
<h2>4. 젠킨스 파이프라인 예시</h2>
<p>필자는 처음에 젠킨슴 파이프라인을 도입하게 된 이유는 여러가지 JOB들을 연계해서 한번에 실행하고 싶었고, 그것을 한눈에 보기 쉽게 대시보드로 보고싶었다.</p>
<p>물론, RUNDECK이라는 CD툴을 이용하면 손쉽게 workflow 구성이 가능하다.<br />
하지만, 젠킨스의 다양한 플러그인들을 포기할 수 없었고, 파이프라인구성으로 RUNDECK처럼 꾸며보고 싶었다.</p>
<p>필자는 다음의 업무를 수행하고 싶었다. (필자의 업무기에 모든 내용을 전달할 순 없지만, 그냥 여러가지 일을 파이프라인으로 연결시키는것에 주목해주길 바랍니다.)</p>
<ul>
<li>라이브 서버에서 SOURCE(컨텐츠)를 추출합니다.</li>
<li>추출한 SOURCE(컨텐츠)를 검증용 서버에 설치합니다.</li>
<li>검증용 서버에서 SOURCE(컨텐츠)를 조작(컨텐츠 url 변경) 합니다.</li>
<li>검증용 서버에서 변경된 SOURCE(컨텐츠)를 추출합니다.</li>
<li>라이브 서버에 변경된 SOURCE(컨텐츠)를 설치합니다.</li>
</ul>
<p>즉, 현재 라이브 서버에 있는 컨텐츠를 가져와서 검증용 서버에서 변경하고, 다시 라이브서로 옮기는 작업이다.</p>
<p>상위의 작업을 진행하려면, 총 5번의 JOB을 수행해야하고, 매번 INPUT을 입력해줘야하기 때문에 실수가 발생할 수 있다.</p>
<pre><code class="line-numbers">def ZIP_FILE

pipeline {
    agent any
    parameters {

        choice(name: 'SOURCE',choices: "라이브 서버1\n라이브 서버2\n라이브 서버3",description: 'SOURCE-SERVER' )

        choice(name: 'TARGET',choices: "검증용 서버1\n검증용 서버2\n검증용 서버3",description: 'TARGET-SERVER' )

        text defaultValue: '''/content/path''', description: '소스 추출', name: 'SOURCECONTENT'

        text defaultValue: '''/content/path''', description: '컨텐츠 카피', name: 'COPYCONTENT'

        text defaultValue: '''/content/path''', description: '타겟 추출', name: 'TARGETCONTENT'

    }
    stages {
        stage('Source - Build') {
            steps {
                script{
                      def myjob=build job: 'LIVE_extract_Server', parameters: [[$class: 'com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterValue', name: 'SERVER', value: "${params.SOURCE}"], string(name: 'TITLE', value: 'B2C_AP_Author_Build_APPS'), password(description: '', name: 'PASSWORD', value: 'password'), text(name: 'FILTER', value: "${params.SOURCECONTENT}")]
                      def jobDisplayName=myjob.getDisplayName()
                      ZIP_FILE = jobDisplayName.split('#')[1] + ".zip"
                }

            }
        }
        stage('Target - Install(ITG)') {
            steps {
                script{
                    def myjob=build job: 'STG_Deploy_Server', parameters: [[$class: 'com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterValue', name: 'SERVER', value: "${params.TARGET}"], string(name: 'TITLE', value: 'B2C_AP_Author_Deploy_APPS'), password(description: '', name: 'PASSWORD', value: 'password'), text(name: 'FILE', value:ZIP_FILE)]
                }
            }
        }
        stage('Target - Copy') {
            steps {
                script{
                    println ZIP_FILE
                    def myjob=build job: 'STG_PageTool_Server_APPS', parameters: [[$class: 'com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterValue', name: 'SERVER', value: "${params.TARGET}"], string(name: 'TITLE', value: 'B2C_AP_Author_Copy_APPS'), password(description: '', name: 'PASSWORD', value: 'password'), string(name: 'ACTION', value:'copy'), text(name: 'PAGE', value:"${params.COPYCONTENT}")]
                }
            }
        }
        stage('Target - Build') {
            steps {
               script{
                      def myjob=build job: 'STG_Build_Server', parameters: [[$class: 'com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterValue', name: 'SERVER', value: "${params.TARGET}"], string(name: 'TITLE', value: 'B2C_AP_Author_Build_APPS_flag'), password(description: '', name: 'PASSWORD', value: 'password'), text(name: 'FILTER', value: "${params.TARGETCONTENT}")]
                      def jobDisplayName=myjob.getDisplayName()
                      ZIP_FILE = jobDisplayName.split('#')[1] + ".zip"
                }
            }
        }
        stage('Source - Upload(LIVE)') {
            steps {
                script{
                    def myjob=build job: 'LIVE_Deploy_Server', parameters: [[$class: 'com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterValue', name: 'SERVER', value: "${params.SOURCE}"], string(name: 'TITLE', value: 'B2C_AP_Author_Deploy_APPS'), password(description: '', name: 'PASSWORD', value: 'password'), text(name: 'FILE', value:ZIP_FILE)]
                }
            }
        }
    }
}
</code></pre>
<p>간단하게 하나씩 설명을 하면,</p>
<ul>
<li>파라미터 셋팅</li>
</ul>
<pre><code class="line-numbers">choice(name: 'SOURCE',choices: "라이브 서버1\n라이브 서버2\n라이브 서버3",description: 'SOURCE-SERVER' )

        choice(name: 'TARGET',choices: "검증용 서버1\n검증용 서버2\n검증용 서버3",description: 'TARGET-SERVER' )

        text defaultValue: '''/content/path''', description: '소스 추출', name: 'SOURCECONTENT'

        text defaultValue: '''/content/path''', description: '컨텐츠 카피', name: 'COPYCONTENT'

        text defaultValue: '''/content/path''', description: '타겟 추출', name: 'TARGETCONTENT'
</code></pre>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/JENKINS_pipe_exam.png?w=1200&#038;ssl=1" alt="Docker Jenkins 파이프라인 사용법 설명 이미지 1" /></p>
<p>2개의 choice 파라미터와, 3개의 멀티라인 파라미터를 셋팅했습니다.</p>
<ul>
<li>job 호출</li>
</ul>
<pre><code class="line-numbers">stage('Source - Build') {
            steps {
                script{
                      def myjob=build job: 'LIVE_extract_Server', parameters: [[$class: 'com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterValue', name: 'SERVER', value: "${params.SOURCE}"], string(name: 'TITLE', value: 'B2C_AP_Author_Build_APPS'), password(description: '', name: 'PASSWORD', value: 'password'), text(name: 'FILTER', value: "${params.SOURCECONTENT}")]
                      def jobDisplayName=myjob.getDisplayName()
                      ZIP_FILE = jobDisplayName.split('#')[1] + ".zip"
                }

            }
        }
</code></pre>
<p>제일 처음에는 stages라는 block으로 전체 stage를 구성해줍니다.<br />
그리고 각각, stgae를 맞춰서 작성합니다.</p>
<p>상위의 예는 1개를 뒀지만, 사실 5개의 job호출 형태는 모두 동일하기 때문에 1개에 대해서만 설명드리겠습니다.</p>
<ol>
<li>스테이지 명시</li>
</ol>
<pre><code class="line-numbers">stage('Source - Build') {
}
</code></pre>
<ol start="2">
<li>스텝 지정</li>
</ol>
<pre><code class="line-numbers">steps {
}
</code></pre>
<ol start="3">
<li>스크립트 작성</li>
</ol>
<pre><code class="line-numbers">script{
                      def myjob=build job: 'LIVE_extract_Server', parameters: [[$class: 'com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterValue', name: 'SERVER', value: "${params.SOURCE}"], string(name: 'TITLE', value: 'B2C_AP_Author_Build_APPS'), password(description: '', name: 'PASSWORD', value: 'password'), text(name: 'FILTER', value: "${params.SOURCECONTENT}")]
                      def jobDisplayName=myjob.getDisplayName()
                      ZIP_FILE = jobDisplayName.split('#')[1] + ".zip"
                }
</code></pre>
<p>스크립트의 설명은 LIVE_extract_Server라는 job을 호출합니다.</p>
<pre><code class="line-numbers">parameters: [[$class: 'com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterValue', name: 'SERVER', value: "${params.SOURCE}"], string(name: 'TITLE', value: 'B2C_AP_Author_Build_APPS'), password(description: '', name: 'PASSWORD', value: 'password'), text(name: 'FILTER', value: "${params.SOURCECONTENT}")]
</code></pre>
<p>파라미터 셋팅 같은 경우,</p>
<p>extendedChoiceParameter</p>
<p>String</p>
<p>password</p>
<p>text</p>
<p>타입으로 파라미터를 넘깁니다.</p>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/JENKINS_pipe_dashboard.png?w=1200&#038;ssl=1" alt="파이프라인 대시보드" /></p>
<h2>5. 마치며</h2>
<p>젠킨스 파이프라인 구성을 알아봤습니다. 정리를 하면, 우선 2가지 타입(선언, 스크립트)이 존재하며, 필자가 설명드린 선언방식의 <code>문법</code> 에 대해서 한가지씩 알아봤습니다.</p>
<p>파이프라인을 사용하는 가장큰 이유는 job들의 workflow 구성일 것입니다. 위의 방식으로 손쉽게 구성을 할 수 있을것이라고 생각이 듭니다.<br />
<a href="http://blog.wonizz.com" title="워니즈 블로그">워니즈 블로그</a><br />
<a href="http://github.com/wonizz" title="워니즈 깃헙" target="_blank" rel="noopener">워니즈 깃헙</a></p>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/08/04/jenkins-pipeline/">[Docker] Jenkins 파이프라인 사용법</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.wonizz.com/2019/08/04/jenkins-pipeline/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">689</post-id>	</item>
		<item>
		<title>[Docker] Jenkins 기본 셋업</title>
		<link>https://blog.wonizz.com/2019/08/03/docker-jenkins-basic-setup/</link>
					<comments>https://blog.wonizz.com/2019/08/03/docker-jenkins-basic-setup/#respond</comments>
		
		<dc:creator><![CDATA[워니]]></dc:creator>
		<pubDate>Sat, 03 Aug 2019 13:08:50 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[도커]]></category>
		<guid isPermaLink="false">http://blog.wonizz.tk/?p=672</guid>

					<description><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
<p>안녕하세요? 정리하는 개발자 워니즈입니다. 지난시간에 Docker 를 사용하여 Jenkins 컨테이너를 올려보는 내용까지 정리를 했습니다. 오늘은 Jenkins 의 기본 셋업에 대해서 알아보겠습니다. Jenkins 도커로 실행하기(1/3) Jenkins 기본 셋업(Docker 내부에서 필요한 툴 설치)(2/3) Jenkins 파이프라인 사용법(3/3) Jenkins 글로벌 Tools Jenkins 필수 플러그인 1. Jenkins 글로벌 Tools 젠킨스에서는 JDK, MAVEN, NODEJS, GIT, GRADLE 등 다양한 도구들을 글로벌하게 셋팅하고&#8230;&#160;</p>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/08/03/docker-jenkins-basic-setup/">[Docker] Jenkins 기본 셋업</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
<p>안녕하세요? 정리하는 개발자 워니즈입니다. 지난시간에 Docker 를 사용하여 Jenkins 컨테이너를 올려보는 내용까지 정리를 했습니다. 오늘은 Jenkins 의 기본 셋업에 대해서 알아보겠습니다.</p>
<p><a href="https://blog.wonizz.com/2019/08/01/docker-jenkins/" title="Jenkins 도커로 실행하기(1/3)">Jenkins 도커로 실행하기(1/3)</a><br />
<a href="https://blog.wonizz.com/2019/08/03/docker-jenkins-basic-setup/" title="Jenkins 기본 셋업(Docker 내부에서 필요한 툴 설치)(2/3)">Jenkins 기본 셋업(Docker 내부에서 필요한 툴 설치)(2/3)</a><br />
<a href="https://blog.wonizz.com/2019/08/04/jenkins-pipeline/" title="Jenkins 파이프라인 사용법(3/3)">Jenkins 파이프라인 사용법(3/3)</a></p>
<ul>
<li>Jenkins 글로벌 Tools</li>
<li>Jenkins 필수 플러그인</li>
</ul>
<h2>1. Jenkins 글로벌 Tools</h2>
<p>젠킨스에서는 JDK, MAVEN, NODEJS, GIT, GRADLE 등 다양한 도구들을 글로벌하게 셋팅하고 각 Job 들에서 호출해서 사용 할 수 있습니다. 마치 공용 도구함을 만들어서 망치, 못, 드릴 등을 넣어두고 다양한 곳에서 쓰이고 있다고 보면 됩니다.</p>
<p>필자는 아래의 도구들을 설치했습니다.</p>
<ul>
<li>openjdk</li>
<li>maven</li>
<li>nodejs + npm</li>
<li>git</li>
<li>gradle</li>
</ul>
<p>우선 글로벌 툴을 셋팅하는 부분은 젠킨스 관리 > 글로벌 도구 설정에서 볼 수 있습니다.</p>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/JENKINS_global.png?w=1200&#038;ssl=1" alt="Docker Jenkins 기본 셋업 설명 이미지 1" /></p>
<p>처음 보게 되는 화면은 jdk, maven 정도의 설정 밖에 없습니다. 이는 아직 연결 시켜주는 플러그인들이 설치 되어 있지 않기 때문입니다. 우선 있는대로, jdk, maven 을 셋팅해봅니다.</p>
<ol>
<li>jdk 설정</li>
</ol>
<p>docker로 jenkins를 올리게되면, 기본적으로 openjdk가 설치 되어있습니다.</p>
<pre><code class="line-numbers">root@1b011b567397:/# java -version
openjdk version "1.8.0_171"
OpenJDK Runtime Environment (build 1.8.0_171-8u171-b11-1~deb9u1-b11)
OpenJDK 64-Bit Server VM (build 25.171-b11, mixed mode)
</code></pre>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/JENKINS_java2.png?w=1200&#038;ssl=1" alt="Docker Jenkins 기본 셋업 설명 이미지 2" /></p>
<p>따라서, jdk는 기본 설정에 /docker-java-home path만 입력 해주면됩니다.</p>
<ol start="2">
<li>maven</li>
</ol>
<p>메이븐 부터는 개별적으로 컨테이너 내부에 설치를 해줘야 합니다.</p>
<p>docker container에 접속하여 다음을 입력합니다.</p>
<pre><code class="line-numbers">#docker container 접속
docker exec -it jenkins /bin/bash

#maven 설치
apt-get update
apt-get install maven

#설치 후 로그 확인
.
.
update-alternatives: using /usr/share/maven/bin/mvn to provide /usr/bin/mvn (mvn) in auto mode

</code></pre>
<p>maven은 기본 설정에 /usr/share/maven path를 입력해주면 됩니다</p>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/JENKINS_maven%2Bjdk.png?w=1200&#038;ssl=1" alt="Docker Jenkins 기본 셋업 설명 이미지 3" /></p>
<ol start="3">
<li>Node.js</li>
</ol>
<p>우분투 16.04의 패키지 저장소에 Node.js가 기본으로 들어가져 있습니다. 이 글을 쓰는 현 시점에 v4.2.6 버전이 저장소에 올려져있습니다.</p>
<p>apt 패키지 매니저를 통해 손쉽게 설치할 수 있습니다.</p>
<pre><code class="line-numbers">#nodejs 설치
sudo apt-get update
sudo apt-get install nodejs

#설치 후 로그 확인
.
.
update-alternatives: using /usr/bin/nodejs to provide /usr/bin/js (js) in auto mode
</code></pre>
<p>이후에 npm 설치를 진행하려 하지만, 에러가 발생합니다.</p>
<pre><code class="line-numbers">#npm 설치
sudo apt-get install npm

#에러 발생
E: Unable to locate package npm
</code></pre>
<blockquote><p>
  A Node.js package is also available in the official repo for Debian Sid (unstable), Jessie (testing) and Wheezy (wheezy-backports) as &#8220;nodejs&#8221;. It only installs a nodejs binary.
</p></blockquote>
<p>Node.js 에서는 특정 버전 이후에는 binary 로 설치할 것을 권장학 있습니다.</p>
<pre><code class="line-numbers">sudo apt install curl
curl -sL https://deb.nodesource.com/setup_6.x | sudo bash -
sudo apt-get install -y nodejs
sudo apt-get install -y npm
</code></pre>
<p>다른 패키지와의 충돌을 방지하기 위해, 우분투 저장소의 Node.js는 node 대신 nodejs 명령어를 사용합니다.</p>
<p>다음 명령어로 정상적으로 Node.js가 설치되었는 지 확인할 수 있습니다.</p>
<p>nodejs는 기본 설정에 /usr/bin path 를 입력해줍니다.</p>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/JENKINS_node.png?w=1200&#038;ssl=1" alt="Docker Jenkins 기본 셋업 설명 이미지 4" /></p>
<h2>2. Jenkins 필수 플러그인</h2>
<p>제목을 필수 플러그인라고 했지만, 사실 필자가 주로 사용하는 플러그인이라고 보면된다. 추천하는 플러그인이고 독자분의 생각에 따라 사용유무를 결정하면 됩니다.</p>
<ul>
<li>Build Name and Description Setter</li>
<li>Dynamic Extended Choice Parameter Plug-In</li>
<li>Extended Choice Parameter</li>
<li>Extensible Choice Parameter plugin</li>
<li>Last Changes</li>
<li>File Operations Plugin</li>
<li>Build Timeout</li>
<li>Workspace Cleanup Plugin</li>
<li>NodeJS</li>
<li>Maven Integration</li>
<li>Git</li>
<li>Gradle</li>
</ul>
<p>상위의 플러그인 중에 소개할만한 내용에 대해서만 정리해보았습니다.</p>
<ol>
<li>Build Name and Description Setter</li>
</ol>
<p>job에서 빌드를 수행하면 기본적으로 $BUILD_NUMBER라고해서 숫자로 BUILD JOB의 name 이 결정됩니다. 가독성도 떨어지고 숫자기때문에 정확하게 추적하기가 어렵습니다. 그래서 필자는 보통 <code>job name + job 수행시간</code>으로 기록을 합니다. BUILD NAME 셋팅을 위한 플러그인이라고 보면됩니다.</p>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/JENKINS_setbuild.png?w=1200&#038;ssl=1" alt="Docker Jenkins 기본 셋업 설명 이미지 5" /></p>
<p>BUILD_DATE에 대한 포맷 지정을 위해서 아래의 내용을 <code>빌드 환경</code>탭에서 입력해줍니다.</p>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/JENKINS_setbuild2.png?w=1200&#038;ssl=1" alt="Docker Jenkins 기본 셋업 설명 이미지 6" /></p>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/JENKINS_setbuild3.png?w=1200&#038;ssl=1" alt="Docker Jenkins 기본 셋업 설명 이미지 7" /></p>
<p>입력하고 나면, 좀더 가독성있고 추적하기도 편리합니다.</p>
<ol start="2">
<li>Extensible Choice Parameter plugin</li>
</ol>
<p>JOB은 보통 파라미터 셋팅에 따라서 다양한 업무를 수행합니다. 따라서 파라미터를 어떻게 넘기느냐가 JOB수행 여부에 중요한 요소입니다. 필자가 속한 프로젝트에서는 수많은 서버에서 반복적인 업무를 하다보니, 파라미터를 여러개 넘겨줘야 합니다.</p>
<p>이 플러그인은 multi choice, single choice, file choice 등 다양한 기능들을 지원합니다.</p>
<ul>
<li>choice parameter</li>
</ul>
<p>초이스는 한개의 싱글 select만 가능합니다.</p>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/JENKINS_choice_test.png?w=1200&#038;ssl=1" alt="Docker Jenkins 기본 셋업 설명 이미지 8" /></p>
<p>위와 같이 test1, test2, test3을 고를 수 있게 입력을 합니다.</p>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/JENKINS_choice_test2.png?w=1200&#038;ssl=1" alt="Docker Jenkins 기본 셋업 설명 이미지 9" /></p>
<ul>
<li>Multi select choice</li>
</ul>
<p>다양하게 선택을 하게끔 해주는 기능을 구현하기 위해서는 extensible choice parameter 플러그인을 이용합니다.</p>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/JENKINS_extend_test.png?w=1200&#038;ssl=1" alt="Docker Jenkins 기본 셋업 설명 이미지 10" /></p>
<p>위와 같이 parameter type을 <code>multi</code> 로 지정을 한뒤 Delimeter는 <code>,</code>로 지정을 하여 파라미터를 나누어줍니다.</p>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/JENKINS_extend_test2.png?w=1200&#038;ssl=1" alt="Docker Jenkins 기본 셋업 설명 이미지 11" /></p>
<ol start="2">
<li>Last Changes</li>
</ol>
<p>젠킨스는 형상관리 레포지토리에 있는 소스를 가져와서 빌드를 수행하고 테스트를 합니다. 그럼 이전 버전과의 차이를 알고 싶을때는 이 플러그인이 유용합니다.</p>
<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/08/JENKINS_chage.png?w=1200&#038;ssl=1" alt="Docker Jenkins 기본 셋업 설명 이미지 12" /></p>
<h2>3.마치며</h2>
<p>젠킨스의 글로벌 도구 설정과 필수 플러그인에 대해서 정리해보았습니다. 젠킨스는 확실히 역사도 길고 다양한 플러그인으로 사용성을 높이고 있습니다. 필자또한 젠킨스를 알게 되면서 반복 단순한 업무들은 모두 job으로 구성하여 한번의 수행으로 해결하고 있습니다.</p>
<p>다음시간에는 젠킨스 파이프라인 구성에 대해서 알아보겠습니다.</p>
<p><a href="http://blog.wonizz.com" title="워니즈 블로그">워니즈 블로그</a><br />
<a href="http://github.com/wonizz" title="워니즈 깃헙" target="_blank" rel="noopener">워니즈 깃헙</a></p>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/08/03/docker-jenkins-basic-setup/">[Docker] Jenkins 기본 셋업</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.wonizz.com/2019/08/03/docker-jenkins-basic-setup/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">672</post-id>	</item>
		<item>
		<title>[Docker] Dockerfile 의 이해</title>
		<link>https://blog.wonizz.com/2019/07/31/docker-dockerfile/</link>
					<comments>https://blog.wonizz.com/2019/07/31/docker-dockerfile/#respond</comments>
		
		<dc:creator><![CDATA[워니]]></dc:creator>
		<pubDate>Wed, 31 Jul 2019 04:50:08 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[도커]]></category>
		<guid isPermaLink="false">http://blog.wonizz.tk/?p=644</guid>

					<description><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
<p>안녕하세요? 정리하는 개발자 워니즈 입니다. 이번 시간에는 도커 파일 에 대해서 알아보도록 하겠습니다. 지난번 docker 이야기는 설치하고 기본적인 사용법과 볼륨에 대해서 알아봤습니다. 이제는 이미지가 어떻게 빌드가 되고, 이미지로부터 container를 어떻게 생성하는지 알아보는 시간을 갖도록 하겠습니다. 1. 도커파일 이란? Dockerfile 도커 파일은 이미지를 생성하기 위한 스크립트이며, 도커 파일 빌드를 하면 완성된 이미지를 얻게 됩니다. 필자는 도커파일은&#8230;&#160;</p>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/07/31/docker-dockerfile/">[Docker] Dockerfile 의 이해</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
안녕하세요? 정리하는 개발자 워니즈 입니다. 이번 시간에는 도커 파일 에 대해서 알아보도록 하겠습니다. 지난번 docker 이야기는 설치하고 기본적인 사용법과 볼륨에 대해서 알아봤습니다. 이제는 이미지가 어떻게 빌드가 되고, 이미지로부터 container를 어떻게 생성하는지 알아보는 시간을 갖도록 하겠습니다.

<h2> </h2>

<h2>1. 도커파일 이란?</h2>

<ul>
<li>Dockerfile</li>
</ul>

<blockquote>
  도커 파일은 이미지를 생성하기 위한 스크립트이며, 도커 파일 빌드를 하면 완성된 이미지를 얻게 됩니다. 
  필자는 도커파일은 마치 이미지를 생성하기 위한 명세서라고 생각합니다. 제 3자가 도커파일만 보고 이 이미지가 어떤 역할을 하는지 어떤식으로 구성이 되어있는지 확인할 수 있습니다.
</blockquote>

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.octo.com/wp-content/uploads/2014/01/docker-stages.png?w=1200&#038;ssl=1" alt="Docker 엔지니어링" title="RubberDuck" />
<a href="https://github.com/search?utf8=%E2%9C%93&#038;q=dockerfile%EF%BF%BC" title="도커파일 예시" target="_blank" rel="noopener">도커파일 예시</a>

위에서 보시는것처럼 Docker에서 이미지를 생성하기 위한 방법은 3가지가 있습니다.

<ol>
<li>도커파일</li>
<li>컨테이너 커밋</li>
<li>이미지 태그</li>
</ol>

이중 가장 일반적이고 CI/CD로 활용되어지는 방법은 Dockerfile로 빌드해 이미지를 생성하는 방법입니다.
필자가 Devops 과제에서 선보인 내용에서 spring-bood app을 그라들 빌드해서 jar파일을 가져오고 Dockerfile에 명세를 젂어서 이미지로 추출하는 내용을 넣었습니다.

Dockerfile은 사용자가 이미지를 생성하기위해 순차적으로 작성한 명령어로 된 Text문서이며, <em>docker build</em> 명령어로 Dockerfile과 Context를 통해 이미지를 생성합니다.

<pre><code class="line-numbers"># mkdir /dockerfile
# cd dockerfile
# gedit dockerfile
</code></pre>

<ul>
<li>이미지 빌드</li>
</ul>

<pre><code class="line-numbers"># docker build --tag myubuntu:1.0 .
# docker images
</code></pre>

-t, &#8211;tag : 저장소 이름, 이미지 이름, 태그를 설정합니다. &lt;저장소 이름>/&lt;이미지 이름>:&lt;태그> 형식

<code>.</code> : Build Context

<ul>
<li>컨테이너 실행</li>
</ul>

<pre><code class="line-numbers">docker run -it --rm --name myubuntu myubuntu:1.0 /bin/bash
</code></pre>

&#8211;name : 컨테이너 명 지정

-d : 컨테이너를 백그라운드로 실행

-it : 터미널모드로 실행

-p 호스트와 컨테이너 포트를 연결해 노출

&#8211;rm 실행 후 컨테이너 자동삭제

<h2>2. 명령어</h2>

<ul>
<li>FROM</li>
</ul>

<pre>FROM <image> [AS <name>]
FROM <image>[:<tag>] [AS <name>]
FROM <image>[@<digest>] [AS <name>]
</pre>

<code>도커파일</code>

<pre><code class="line-numbers">FROM ubuntu:18.04

# Container에서 실행할 명령
CMD ["/bin/echo", "hello docker"]
</code></pre>

<code>이미지 빌드</code>

<pre><code class="line-numbers"># docker build -t localhost:5000/myununtu:v2 .
# docker run localhost:5000/myununtu:v2
</code></pre>

<ul>
<li>LABEL</li>
</ul>

<code>LABEL</code> instruction는 Label로 지정한 문자열을 이미지에 메타데이터로 추가합니다.

<code>LABEL</code> 은 key-value 쌍으로 작성하며 , space를 포함시키기 위해서는 따옴표(<code>""</code>)를 이어쓰기를 위해서는 백슬래쉬(<code>\</code>)를 사용하면 됩니다.

<pre>LABEL <key>=<value> <key>=<value> <key>=<value> ...
</pre>

도커파일

<pre><code class="line-numbers">FROM ubuntu:18.04

LABEL multi.label1="value1" multi.label2="value2" other="value3"
LABEL multi.label1="value1" \
      multi.label2="value2" \
      other="value3"

# Container에서 실행할 명령
CMD ["/bin/echo", "hello docker"]
</code></pre>

이미지 빌드

<pre><code class="line-numbers"># docker build -t localhost:5000/myununtu:v2 .
# docker run -it localhost:5000/myununtu:v2 /bin/bash
</code></pre>

이렇게 추가된 Lavel은 컨테이너 실행시 <code>docker inspect</code> 명령어로 내용을 확인 할 수 있습니다.

다만 주의할 것은  Base 이미지에 포함된 Lavel 값이 상속된다는 점이고, 만약 같은 Lavel값이 존재한다면 가장 최근에 적용된 Lavel값이 우선합니다.

<pre><code class="line-numbers">"Labels": {
    "com.example.vendor": "ACME Incorporated"
    "com.example.label-with-value": "foo",
    "version": "1.0",
    "description": "This text illustrates that label-values can span multiple lines.",
    "multi.label1": "value1",
    "multi.label2": "value2",
    "other": "value3"
},
</code></pre>

<ul>
<li>RUN

<code>RUN</code> instruction는 Base Image위에 필요한 패키지를 설치할 때 사용하는 명령어입니다.. <code>Run</code>명령어가 수행된 이후에는 새로운 Layer가 Base이미지 위에 생성됩니다.</p></li>
</ul>

shell form : command 로 입력받은 명령어는 쉘에서 수행되며 디폴트로 리눅스에서는 /bin/sh -c 이 윈도우에서는 cmd /S /C 가 사용됩니다.

<pre><code class="line-numbers">RUN <command>
</code></pre>

<pre>RUN ["executable", "param1", "param2"]
</pre>

<code>도커파일</code>

<code>RUN</code> instruction은 현재생성된 이미지의 위의 새로운 레이어를 생성하여 그 안에서 명령어를 수행하고 그 결과를 레이어에 commit합니다. 따라서 \ (backslash)를 사용하여 RUN을 수행한 것과 여러개의 RUN을 수행한 것은 결과는 동일하나 생성된 레이어의 갯수가 차이가 있게 됩니다.

<pre><code class="line-numbers">FROM ubuntu:14.04
RUN apt-get update
RUN apt-get install -y package-a
RUN apt-get install -y package-b
RUN apt-get install -y package-c
</code></pre>

<pre><code class="line-numbers">FROM ubuntu:14.04
RUN apt-get update && apt-get install -y \
        package-a \
        package-b \
        package-c
</code></pre>

<ul>
<li>CMD

<code>CMD</code> instruction은 Docker Container가 시작할때 실행 할 커맨드를 지정하는 지시자이며 아래와 같은 특징과 기능을 제공합니다.

</li>
</ul>

<ol>
<li><strong>CMD의 주용도는 컨테이너를 실행할 때 사용할 default 명령어를 설정</strong>하는 것입니다.<code>docker run</code> 실행 시 실행할 커맨드를 주지 않으면 CMD로 지정한 default 명령이 실행됩니다.</li>
<li><code>ENTRYPOINT</code>의 파라미터를 설정할 수도 있습니다.</li>
<li><code>RUN</code> instruction 과 기능은 비슷하지만 차이점은 <code>CMD</code>는 docker image를 빌드할때 실행되는 것이 아니라 docker container가 시작될때 실행됩니다. 주로 docker image로 빌드된 application을 실행할때 사용됩니다.</li>
</ol>

<code>CMD</code> instruction 는 아래와 같이 3가지 포맷을 지원합니다.

<ol>
<li><code>CMD ["executable","param1","param2"]</code> (<em>exec</em> form, this is the preferred form)</li>
<li><code>CMD ["param1","param2"]</code> (as <em>default parameters to ENTRYPOINT</em>)</li>
<li><code>CMD command param1 param2</code> (<em>shell</em> form)</li>
</ol>

<code>도커 파일</code>

<pre><code class="line-numbers">FROM ubuntu
...
CMD ["apache2","-DFOREGROUN"]
</code></pre>

<pre><code class="line-numbers">FROM ubuntu
...
CMD ["python"]
</code></pre>

<pre><code class="line-numbers">FROM ubuntu
CMD echo "This is a test."
</code></pre>

<pre><code class="line-numbers">FROM ubuntu
CMD ["/usr/bin/wc","--help"]
</code></pre>

<ul>
<li>ENTRYPOINT</li>
</ul>

Docker image가 실행될때 기본 command를 지정합니다. <code>CMD</code>와 비슷하지만 <code>CMD</code>는 override 가 가능하지만 <code>ENTRYPOINT</code> 는 override 할 수 없습니다. 대신에 <code>docker run</code> 커맨드로 추가하는 커맨드들은 <code>ENTRYPOINT</code> instruction에 지정된 커맨드에 옵션으로 추가됩니다.

<code>ENTRYPOINT</code> instruction 는 아래와 같이 2가지 포맷을 지원합니다.

<ul>
<li><code>ENTRYPOINT ["executable", "param1", "param2"]</code> (<em>exec</em> form, preferred)</li>
<li><code>ENTRYPOINT command param1 param2</code> (<em>shell</em> form)</li>
</ul>

<code>도커파일</code>

<pre><code class="line-numbers">FROM ubuntu
ENTRYPOINT ["/bin/echo", "Hello world"]
</code></pre>

<code>ENTRYPOINT & CMD instruction 예제</code>

<pre><code class="line-numbers">FROM centos
ENTRYPOINT ["/bin/echo", "Hello world"]
CMD ["world"]
</code></pre>

<pre><code class="line-numbers"># gedit dockerfile

# docker build --tag localhost:5000/hello:1.1 .

컨테이너를 실행에 어떤 내용이 출력되는지 확인해봅시다.
# docker run -it localhost:5000/hello:1.1
# docker run -it localhost:5000/hello:1.1 cmdtest
</code></pre>

<ul>
<li>EXPOSE</li>
</ul>

<code>EXPOSE</code> 명령은 Container가 Runtime시 수신대기할 포트를 지정하는 명령어입니다. 포트번호 및 TCP 또는 UDP를 지정할 수 있으며 프로토콜이 지정되지 않을 경우 기본값은 TCP입니다.

주의해야할 점은 EXPOSE 명령어 자체가 실제로 포트를 열지 않는다는 점입니다. EXPOSE 명령은 이미지를 만드는 사람과 이미지를 사용하는 사람이 포트 및 프로토콜 규약을 명시해놓은 문서기능을 하는 것이고 실제 Container의 포트는 docker run -p 옵션으로 Container를 실행하는 시점에 -p 옵션으로 지정된 포트가 개방됩니다.

<pre>EXPOSE <port> [<port>/<protocol>...]
</pre>

<code>도커파일</code>

<pre><code class="line-numbers">EXPOSE 80/udp
EXPOSE 80/tcp
</code></pre>

<ul>
<li>ENV</li>
</ul>

<code>ENV</code>명령어는 환경변수 <code><key></code> 를 <code><value></code>로 설정하는 지시자입니다. 쉽게 일반 프로그래밍에서 변수를 지정하는 것과 동일하다고 생각하면 됩니다.

<code>ENV</code>를 사용하여 셋팅된 환경변수는 Container Runtime시에도 셋팅된 변수가 유지됩니다.

<pre>ENV <key> <value>
ENV <key>=<value> ...
</pre>

<code>도커파일</code>

<pre><code class="line-numbers">FROM busybox
ENV FOO /bar
WORKDIR ${FOO}   # WORKDIR /bar
COPY . /quux # COPY all to /quux
</code></pre>

<ul>
<li>COPY</li>
</ul>

호스트의 Context 내의 파일 또는 디렉터리들을 Container의 파일시스템으로 복사하는 명령어입니다. 또한 <code>--chown</code> 옵션으로 파일 및 디렉터리에 대한 유저와 그룹을 지정할 수 있습니다

<ol>
<li>COPY [&#8211;chown=<user>:<group>] <src>&#8230; <dest>`</li>
<li><code>COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]</code> (this form is required for paths containing whitespace)</li>
</ol>

<code>도커 파일</code>

<pre><code class="line-numbers">COPY . /bar/             # adds all files and directories
COPY test.jar /bin/test/ # adds a test.jar file
COPY hom* /mydir/        # adds all files starting with "hom"
COPY hom?.txt /mydir/    # ? is replaced with any single character, e.g., "home.txt"
COPY --chown=55:mygroup files* /somedir/
COPY --chown=bin files* /somedir/
COPY --chown=1 files* /somedir/
COPY --chown=10:11 files* /somedir/
</code></pre>

<code>COPY --chown</code>에 의해 주어진 유저명과 그룹명으로 지정되지 않은 모든 파일 및 디렉터리들은 Container안에서 UID, GID 0번으로 생성됩니다.

<ul>
<li>ADD</li>
</ul>

ADD는 Syntax 및 기능면에서 COPY와 유사 URL을 지정해 파일을 복사 할 수 있고 압축파일(tar)을 을 자동으로 풀어서 복사한다는 점에서 차이가 있습니다.

<ol>
<li>ADD [&#8211;chown=<user>:<group>] <src>&#8230; <dest>`</li>
<li><code>ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]</code>(this form is required for paths containing whitespace)</li>
</ol>

<code>도커 파일</code>

<pre><code class="line-numbers">ADD http://example.com/big.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
RUN make -C /usr/src/things all
</code></pre>

<ul>
<li>USER</li>
</ul>

Docker로 Container를 수행할때 Container 실행 유저는 Docker의 기본설정으로 root계정입니다.

<pre>root@ubuntu:/# docker run ubuntu whoami
root
</pre>

USER 명령어는 이러한 Container안에서 명령을 실행 할 유저명과 유저그룹을 설정하는 명령어이며, Dockerfile 안에서 USER명령어를 셋팅한 이후의 RUN, CMD, ENTRYPONT 명령어에 적용됩니다.

<pre><code class="line-numbers">USER <user>[:<group>] or
USER <UID>[:<GID>]
</code></pre>

<code>도커 파일</code>

<pre><code class="line-numbers"># 시스템 그룹 및 유저로 postgres를 추가한다. 
RUN groupadd -r postgres && useradd --no-log-init -r -g postgres postgres

# Run the rest of the commands as the `postgres` user
USER postgres
</code></pre>

<ul>
<li>WORKDIR</li>
</ul>

WORKDIR<code>명령어는</code>WORKDIR<code>명령어에 뒤따르는</code>WORKDIR<code>,</code>RUN<code>,</code>CMD<code>,</code>ENTRYPOINT<code>,</code>COPY<code>,</code>ADD`명령어의 작업디렉터리를 지정하는 명령어입니다. 쉽게 말해 리눅스 cd명령어와 비슷하다고 생각하면 됩니다.

<pre><code class="line-numbers">WORKDIR /path/to/workdir
</code></pre>

<code>도커 파일</code>

<pre><code class="line-numbers">WORKDIR /a   # 작업디렉터리를 /a로 이동합니다
WORKDIR b    # /a에서 하위의 b디렉터리로 이동합니다.
WORKDIR c    # /a/b에서 하위의 c디렉터리로 이동합니다.
RUN pwd      # RUN명령어가 실행되는 디렉터리는 WORKDIR로 이동한 /a/b/c가 됩니다.
</code></pre>

주의할 점은, Linux cd명령어와는 다르게 만약 <code>WORKDIR</code>로 지정한 디렉터리가 존재하지 않을 경우, 그 디렉터리를 Container 안에 생성한다는 점에서 다릅니다.

아래와 같이 <code>ENV</code>로 지정한 환경변수와 함께 쓰일 수 있다는 점도 참고바랍니다.

<pre><code class="line-numbers">ENV DIRPATH /path
ENV DIRNAME dname
WORKDIR $DIRPATH/$DIRNAME
RUN pwd                   # 출력결과 /path/dname
</code></pre>

<ul>
<li>VOLUME</li>
</ul>

<code>VOLUME</code> 은 컨테이너에서 생성된 데이터를 영구보존하고자 할때 사용되는 명령어로 컨테이너가 실행될때 Volume 명령어로 선언된 Container 안의 지점을 Container 밖의 특정지점과 자동으로 마운트되어 컨테이너가 실행됩니다.

이때 Host에 생성되는 경로는 /var/lib/docker/volumes/{volume_name}이고, volume_name은 Docker에서 생성하는 해쉬값으로 생성이됩니다.

<pre><code class="line-numbers">VOLUME ["/data"]
</code></pre>

<code>도커 파일</code>

<pre><code class="line-numbers">FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol
CMD ["/bin/bash"]
</code></pre>

생성한 이미지를 실행하여 볼륨을 조회해 보면 신규로 볼륨을 조회해보면 신규로 한개가 생긴것을 확인할 수 있고 생성된 볼륨디렉터리로 들어가면 dockerfile에서 생성한 file을 확인 할 수 있습니다.

<pre><code class="line-numbers">root@ubuntu:/dockerfile# docker volume ls
DRIVER              VOLUME NAME
local               fbfdbb0b0236c712bd8f2034aa699e0a23a6449915fad90cc0ae07e7f570b0a9
root@ubuntu:/dockerfile# cd /var/lib/docker/volumes && ls
fbfdbb0b0236c712bd8f2034aa699e0a23a6449915fad90cc0ae07e7f570b0a9  metadata.db

root@ubuntu:/var/lib/docker/volumes# cd fbfdbb0b0236c712bd8f2034aa699e0a23a6449915fad90cc0ae07e7f570b0a9
root@ubuntu:/var/lib/docker/volumes/fbfdbb0b0236c712bd8f2034aa699e0a23a6449915fad90cc0ae07e7f570b0a9# ls
_data
root@ubuntu:/var/lib/docker/volumes/fbfdbb0b0236c712bd8f2034aa699e0a23a6449915fad90cc0ae07e7f570b0a9# cd _data/
root@ubuntu:/var/lib/docker/volumes/fbfdbb0b0236c712bd8f2034aa699e0a23a6449915fad90cc0ae07e7f570b0a9/_data# ls
greeting
</code></pre>

이렇게 dockerfile에서만 Volume을 명시해두고 docker실행시 디폴트로 마운트하게되면, docker에서 자동으로 volume을 생성해주지만, Hash값으로 생성하기 때문에 관리하기가 쉽지 않습니다.

따라서 앞서 배운 내용을 바탕으로 Volume을 사전에 미리 생성해두고, 실행시 dockerfile 안에 명시된 경로로 마운트해보도록하겠습니다.

<pre><code class="line-numbers">root@ubuntu:/# docker volume create volume2
volume2
root@ubuntu:/# docker volume ls
DRIVER              VOLUME NAME
local               fbfdbb0b0236c712bd8f2034aa699e0a23a6449915fad90cc0ae07e7f570b0a9
local               volume2
</code></pre>

Volume을 컨테이너 기동시 마운트하면 이 디렉터리가 컨테이너의 지정된 디렉터리로 마운트됩니다.

<pre><code class="line-numbers"># docker run -it --name volumetest --mount source=volume2,target=/myvol localhost/volumetest:v1 /bin/bash
root@a52260c673a7:/# cd /myvol && ls
greeting
root@a52260c673a7:/myvol# exit

root@ubuntu:/# cd /var/lib/docker/volumes/volume2/_data/ && ls
greeting
</code></pre>

명령어를 정리하면서 다음과 같은 명령어는 혼동해서 사용하면 안될 것 같았습니다.

<ol>
<li>COPY vs ADD</li>
<li>RUN vs CMD</li>
<li>ENTRYPOINT &#038; CMD</li>
</ol>

<h2>3. 실습 예제</h2>

<ol>
<li>아래 주석의 내용을 dockerfile로 완성해보세요

시작하기 전 index.html 파일은 아래와 같이 만드시면 됩니다.

<pre><code class="line-numbers"># echo hello world! > index.html

# gedit dockerfile
</code></pre>

<pre><code class="line-numbers"># Base 이미지는 nginx 1.14.1 버전으로 한다.
# author는 guest이다
# 환경변수로 아래 내용을 셋팅한다.
# HTTP_PROXY "http://70.10.15.10:8080"
# HTTPS_PROXY "http://70.10.15.10:8080"
# FTP_PROXY "http://70.10.15.10:8080"
# http_proxy "http://70.10.15.10:8080"
# https_proxy "http://70.10.15.10:8080"
# ftp_proxy "http://70.10.15.10:8080"
# 패키지를 update한다.
# apt-get update
# index.html 파일을 /usr/share/nginx/html 디렉터리로 복사한다.

# 컨테이너에 tcp 80 포트을 개방한다.

# 컨테이너 시작시 필수로 아래 명령어를 수행한다.
# ["nginx"]

# 컨테이너 시작후 nginx의 실행 옵션으로 ["-g", "daemon off;"]를 수행한다.
</code></pre></li>
<li>완성된 docker file을 build 해보세요

</li>
<li>

빌드된 이미지 실행해 Host의 8080으로 포트를 매핑하고 터미널로 연결해보세요

</li>
<li>

연결된 터미널에서 curl localhost:8080  명령으로 nginx가 정상적으로 동작하는지 확인해보세요

</li>
</ol>

<pre><code class="line-numbers"># Base 이미지는 nginx 1.14.1 버전으로 한다.
FROM nginx:1.14.1


# 환경변수로 아래 내용을 셋팅한다.
ENV HTTP_PROXY "http://70.10.15.10:8080"
ENV HTTPS_PROXY "http://70.10.15.10:8080"
ENV FTP_PROXY "http://70.10.15.10:8080"
ENV http_proxy "http://70.10.15.10:8080"
ENV https_proxy "http://70.10.15.10:8080"
ENV ftp_proxy "http://70.10.15.10:8080"

# 패키지를 update한다.
RUN apt-get update

# index.html 파일을 /usr/share/nginx/html 디렉터리로 복사한다.
COPY index.html /usr/share/nginx/html/

# 컨테이너에 tcp 80 포트을 개방한다.
EXPOSE 80/tcp

# 컨테이너 시작시 필수로 아래 명령어를 수행한다.
# ["nginx"]
ENTRYPOINT ["nginx"]

# 컨테이너 시작후 nginx의 실행 옵션으로 ["-g", "daemon off;"]를 수행한다.
CMD ["-g", "daemon off;"]
</code></pre>

<ol>
<li>완성된 docker file을 build 해보세요

docker build -t localhost:5000/mynginx:1.0 .</p></li>
<li>빌드된 이미지 실행해 Host의 8080으로 포트를 매핑하고 터미널로 연결해보세요

docker run -d -p 8080:80 localhost:5000/mynginx:1.0</p></li>
<li>연결된 터미널에서 curl localhost:8080명령으로 nginx가 정상적으로 동작하는지 확인해보세요

curl localhost:8080</p></li>
</ol>

<h2>4. 마치며</h2>

이번 시간에는 도커파일이 어떤것이고 각 명령어에 대해서 알아봤으며, 최종적으로 실습예제를 통해서 사용법을 개괄적으로 보았습니다. 확실히 도커파일이 있으면 명시적으로 어떤 이미지인지 명세를 알 수 있으며, 도커파일만 있다면 언제 어디서든지 도커 이미지를 생성해 낼 수 있기에 굉장히 편리합니다.

다음시간에는 도커의 CI/CD에 대해서 살펴보겠습니다.

<a href="http://blog.wonizz.com" title="워니즈 블로그">워니즈 블로그</a>
<a href="http://github.com/wonizz" title="워니즈 깃헙" target="_blank" rel="noopener">워니즈 깃헙</a>
<h2 class="wp-block-heading">함께 보면 좋은 글</h2>
<ul class="wp-block-list"><li><a href="https://blog.wonizz.com/2019/07/29/docker-volume/">[Docker] Volume 의 관리</a></li><li><a href="https://blog.wonizz.com/2019/07/27/docker-network/">[Docker] 네트워크의 이해</a></li><li><a href="https://blog.wonizz.com/2019/08/08/ansible-role-include/">[Ansible] 플레이북 Role 과 Include</a></li><li><a href="https://blog.wonizz.com/2019/08/13/docker-compose/">[Docker] Compose 구성과 사용법</a></li></ul>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/07/31/docker-dockerfile/">[Docker] Dockerfile 의 이해</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.wonizz.com/2019/07/31/docker-dockerfile/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">644</post-id>	</item>
		<item>
		<title>[Docker] Volume 의 관리</title>
		<link>https://blog.wonizz.com/2019/07/29/docker-volume/</link>
					<comments>https://blog.wonizz.com/2019/07/29/docker-volume/#respond</comments>
		
		<dc:creator><![CDATA[워니]]></dc:creator>
		<pubDate>Mon, 29 Jul 2019 04:12:06 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[도커]]></category>
		<guid isPermaLink="false">http://blog.wonizz.tk/?p=636</guid>

					<description><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
<p>Docker 에서 데이터를 관리하는 방법에 관한 내용으로, Docker로 컨테이너를 실행 후 컨테이너 안에서 파일을 생성하면 Docker의 기본설정으로 모든 파일들을 컨테이너 안의 writable layer에 저장됩니다. 하지만 이러한 매커니즘은 실제 시스템 운영환경에서는 많은 문제를 가지고 있습니다. 예를 들어 컨테이너에서 생성한 파일들이 컨테이너가 재시작되더라도 유지되어야 한다면, 아래의 내용을 생각해 보아야 합니다. 컨테이너가 중지되면 데이터는 컨테이너와 함께 제거되고, 유지되지&#8230;&#160;</p>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/07/29/docker-volume/">[Docker] Volume 의 관리</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
Docker 에서 데이터를 관리하는 방법에 관한 내용으로, Docker로 컨테이너를 실행 후 컨테이너 안에서 파일을 생성하면 Docker의 기본설정으로 모든 파일들을 컨테이너 안의 writable layer에 저장됩니다.

하지만 이러한 매커니즘은 실제 시스템 운영환경에서는 많은 문제를 가지고 있습니다. 예를 들어 컨테이너에서 생성한 파일들이 컨테이너가 재시작되더라도 유지되어야 한다면, 아래의 내용을 생각해 보아야 합니다.

<ul>
<li>컨테이너가 중지되면 데이터는 컨테이너와 함께 제거되고, 유지되지 않습니다.</li>
<li>다른 프로세스 또는 애플리케이션에서 컨테이너 안의 데이터를 사용하기 위해 컨테이너 밖으로 데이터를 가져오는 것은 번거롭거나 어려운 작업이 될 수 있습니다.</li>
<li>컨테이너의 writable layer에 데이터를 기록하기 위해서는 파일스시템을 관리 할 <a href="https://docs.docker.com/storage/storagedriver/" target="_blank" rel="noopener">storage driver</a> 가 필요합니다. storage driver는 리눅스의 커널을 이용해서 union filesystem을 제공하기때문에 이러한 추가적인 추상화로 인해 Host 파일시스템에 직접 데이터를 기록하는 것과 비교해보면 성능측면에서 약점으로 작용합니다.</li>
</ul>

Docker에서는 컨테이너가 중지되더라도 데이터를 유지하기 위한 방법으로  Host 머신에 파일을 저장하는 3가지 방법을 제공합니다.

<ul>
<li>Volume</li>
<li>Bind mount</li>
<li>Tmpfs mount (On Linux)</li>
</ul>

<h2>1. Volume 타입의 선택</h2>

위에서 언급한 3가지 유형의 어떤 마운트 방법을 사용하던, 컨테이너에서 보여지는 데이터는 동일하지만, 3가지 유혀의 Mount는 Host의 어떠한 영역에 마운트되느냐에 차이점이 있습니다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/docs.docker.com/storage/images/types-of-mounts.png?w=1200&#038;ssl=1" alt="types of mounts and where they live on the Docker host" />

<ul>
<li>Volumes** : Docker에 의해 관리되는 Host 파일시스템 영역에 데이터를 저장합니다.

(<code>/var/lib/docker/volumes/</code> on Linux).

Docker에 의해 관리되고, Non-Docker process는 이 영역을 수정할 수 없으므로 Volume은 Docker에서 영구데이터를 관리하는 가장 좋은 방법입니다.</p></li>
<li><strong>Bind mounts</strong> : Host 머신의 파일시스템 어디에나 파일을 저장할 수 있는 방법입니다. Docker외의 다른 프로세스에서 데이터의 접근과 수정이 가능합니다.</p></li>
<li><strong>tmpfs mounts</strong> : Host의 메모리에 데이터를 저장하는 방법입니다.</p></li>
</ul>

<h2>2. Volume 타입의 상세</h2>

<ul>
<li>volume</li>
</ul>

Docker에 의해 만들어지고 관리되는 Volume은  <code>docker volume create</code> 명령어로 명시적으로 Volume을 생성할 수 있습니다.

<pre><code class="line-numbers">root@ubuntu:/# docker volume create volume1
volume1

root@ubuntu:/# docker volume ls
DRIVER              VOLUME NAME
local               volume1
</code></pre>

Volume을 생성하면 Docker Host 머신의 Docker에서 관리하는 디렉터리에 저장됩니다.

<pre><code class="line-numbers">root@ubuntu:/# docker volume inspect volume1
[
    {
        "CreatedAt": "2019-02-22T02:25:12+09:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/volume1/_data",
        "Name": "volume1",
        "Options": {},
        "Scope": "local"
    }
]

root@ubuntu:/# ls /var/lib/docker/volumes/
metadata.db  volume1
</code></pre>

Volume을 컨테이너 기동시 마운트하면 이 디렉터리가 컨테이너의 지정된 디렉터리로 마운트됩니다.

<pre><code class="line-numbers">root@ubuntu:/# docker run -it --name myubuntu --mount source=volume1,target=/volumedata ubuntu
root@da5fe2af29c5:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  volumedata
root@da5fe2af29c5:/# cd volumedata/
root@da5fe2af29c5:/volumedata# touch hellovolume
root@da5fe2af29c5:/volumedata# ls
hellovolume
root@da5fe2af29c5:/volumedata# exit
exit

root@ubuntu:/# cd /var/lib/docker/volumes/volume1/_data/
root@ubuntu:/var/lib/docker/volumes/volume1/_data# ls
hellovolume
</code></pre>

Container 정보를 살펴보면 기본설정으로 Volume의 읽기쓰기모드가 RW(읽기쓰기) 인 것을 알 수 있습니다.

<code>--mount</code> 옵션에 <code>readonly</code> 옵션을 주어 읽기쓰기 모드를 변경 할 수 있습니다

<pre><code class="line-numbers">root@ubuntu:/# docker inspect myubuntu
[
    {
        "Id": "f6369bab35f2c89c0e0fed76c024decc4c19707aa833f6407fc0b1f60f42c38c",
        "Created": "2019-02-21T23:40:56.46535649Z",
        "Path": "/bin/bash",
        "Args": [],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 29553,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2019-02-21T23:40:57.125309312Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
       ...
        "Mounts": [
            {
                "Type": "volume",
                "Name": "volume1",
                "Source": "/var/lib/docker/volumes/volume1/_data",
                "Destination": "/volumedata",
                "Driver": "local",
                "Mode": "z",
                "RW": true,
                "Propagation": ""
            }
        ],

</code></pre>

<pre><code class="line-numbers"># docker run -it --name myubuntu1 --mount source=volume1,target=/volumedata,readonly ubuntu

# docker inspect myubuntu1
[
    {
        "Id": "47e5ba4a6746ab416e2b1985040805cc7574c368989ae9d9dbe6d2186236ba33",
        "Created": "2019-02-21T23:46:07.024314426Z",
        "Path": "/bin/bash",
        "Args": [],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 29663,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2019-02-21T23:46:07.413027114Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
       ...
        "Mounts": [
            {
                "Type": "volume",
                "Name": "volume1",
                "Source": "/var/lib/docker/volumes/volume1/_data",
                "Destination": "/volumedata",
                "Driver": "local",
                "Mode": "z",
                "RW": false,
                "Propagation": ""
            }
        ],
        ...

root@47e5ba4a6746:/volumedata# touch test
touch: cannot touch 'test': Read-only file system
</code></pre>

Volume은 동시에 여러 컨테이너에 마운트 할 수 있으며, 자동으로 Volume이 제거되지 않습니다.

Volume을 제거하기 위해서는 <code>docker volume rm</code>,  <code>docker volume prune</code>  명령어로 제거 할 수 있습니다.

<pre><code class="line-numbers"># docker volume rm volume1
</code></pre>

사용하지 않은 Volume을 제거하기 <code>docker volume prune</code>  명령어로 정리 할 수 있습니다.

<pre><code class="line-numbers"># docker volume prune
</code></pre>

volume 관련 명령어

<table>
<thead>
<tr>
  <th>Command</th>
  <th>Description</th>
</tr>
</thead>
<tbody>
<tr>
  <td><a href="https://docs.docker.com/engine/reference/commandline/volume_create/" target="_blank" rel="noopener">docker volume create</a></td>
  <td>Create a volume</td>
</tr>
<tr>
  <td><a href="https://docs.docker.com/engine/reference/commandline/volume_inspect/" target="_blank" rel="noopener">docker volume inspect</a></td>
  <td>Display detailed information on one or more volumes</td>
</tr>
<tr>
  <td><a href="https://docs.docker.com/engine/reference/commandline/volume_ls/" target="_blank" rel="noopener">docker volume ls</a></td>
  <td>List volumes</td>
</tr>
<tr>
  <td><a href="https://docs.docker.com/engine/reference/commandline/volume_prune/" target="_blank" rel="noopener">docker volume prune</a></td>
  <td>Remove all unused local volumes</td>
</tr>
<tr>
  <td><a href="https://docs.docker.com/engine/reference/commandline/volume_rm/" target="_blank" rel="noopener">docker volume rm</a></td>
  <td>Remove one or more volumes</td>
</tr>
</tbody>
</table>

<ul>
<li>Bind mount</li>
</ul>

Bind mount는 Volume에 비해 기능이 제한되어 있습니다. Bind mount를 사용하면 Container를 Host 머신의 특정 파일이나 디렉터리로 마운트합니다. Host의 마운트 경로는 Full Path를 사용하는데, 해당 파일이나 경로가 존재하지 않을 경우 자동생성되어지기때문에 미리 생성되어 있을 필요는 없습니다.

<pre><code class="line-numbers"># docker run -it -v /volume/bindmount:/data/bindmount ubuntu
root@b1f8e57c3314:/data/bindmount# cd /data/bindmount
root@b1f8e57c3314:/data/bindmount# touch testfile
root@b1f8e57c3314:/data/bindmount# ls
testfile
root@b1f8e57c3314:/data/bindmount# exit
root@ubuntu:/# cd /volume/bindmount/
root@ubuntu:/volume/bindmount# ls
testfile
</code></pre>

Bind mount는 Volume에 비해 아래와 같은 불리한 점이 있기 때문에 가능하다면 Volume을 사용하는 것이 권장됩니다.

<ol>
<li>Bind mount는 Host의 디렉터리 구조에 의존적입니다.</li>
<li>Docker에 의해 관리되어지지 않습니다.</li>
<li>Container안의 프로세스가 Host의 파일시스템을 변경할 수 있으므로 보안상 위협이 될 수 있습니다.</li>
</ol>

<ul>
<li>tmpfs mounts</li>
</ul>

<code>tmpfs</code> mount는 디스크에 데이터를 영구적으로 저장하지 않고 Host의 메모리에 저장합니다. 이러한 특징 때문에 tmfs mount Container의 생명주기와 맞춰서 데이터를 보존하고자 할 때 사용되어질 수 있습니다. 예를 들어, 내부적으로 Docker swarm service는 tmpfs mount를 사용하여 컨테이너 안으로 secret을 마운트합니다.

<h2>3. 예제</h2>

docker 데이터 볼륨으로 데이터 공유를 해보겠습니다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/07/DV_exam.jpg?w=1200&#038;ssl=1" alt="Docker Volume 의 관리 설명 이미지 1" />

다음 명령을 실행하여 컨테이너를 생성하고 데이터 볼륨을 설정합니다. 컨테이너의 Bash 셸이 실행되면 /data 디렉터리로 이동한 뒤 world라는 빈 파일을 생성합니다. 그리고 exit를 입력하여 Bash 셸에서 빠져나옵니다.

<pre><code class="line-numbers">$ sudo docker run -i -t --name hello-volume1 -v /root/data:/data ubuntu /bin/bash
root@f7baf3abefee:/# cd /data
root@f7baf3abefee:/data# touch world
root@f7baf3abefee:/data# exit
</code></pre>

데이터 볼륨 옵션은 -v &lt;호스트 디렉터리>:&lt;컨테이너 디렉터리> 형식입니다. 여기서는 호스트의 /root/data 디렉터리를 Docker 컨테이너의 /data 디렉터리에 연결합니다.

/root/data 디렉터리의 파일 목록을 출력합니다.

<pre><code class="line-numbers">$ sudo ls /root/data
world
</code></pre>

앞에서 생성한 world 파일이 보입니다.

이제 두 번째 컨테이너를 생성합니다. 컨테이너의 Bash 셸이 실행되면 /data 디렉터리의 파일 목록을 출력합니다.

<pre><code class="line-numbers">$ sudo docker run -i -t --name hello-volume2 -v /root/data:/data ubuntu /bin/bash
root@af5a7bdb3e5a:/# ls /data
world
</code></pre>

앞에서 생성한 world 파일이 hello-volume2 파일에서도 보입니다. /data 디렉터리에 파일을 생성하면 호스트 및 hello-volume1 컨테이너에서도 사용할 수 있습니다. 이렇게 데이터 볼륨 설정을 통해 컨테이너끼리 데이터를 공유할 수 있습니다.

디렉터리뿐만 아니라 호스트의 파일 하나만 컨테이너에 연결할 수도 있습니다.

<pre><code class="line-numbers">$ sudo docker run -i -t --name hello-volume -v /root/hello.txt:/root/hello.txt \
    ubuntu /bin/bash
</code></pre>

<h2>4. 마치며</h2>

이상으로 docker volume에 대해서 알아봤습니다. 필자 같은 경우는 주로, bind mount방식으로 많이 사용하고 있습니다. 
정확하게 어떠한 방식이 더 좋다라고는 말씀드리기 어렵지만, 각 자의 방식에 맞춰서 유동적으로 사용하시면 될것 같습니다.

다음시간에는 Compose 구성과 사용법에 대해서 알아보겠습니다.

<a href="http://blog.wonizz.com" title="워니즈 블로그">워니즈 블로그</a>
<a href="http://github.com/wonizz" title="워니즈 깃헙" target="_blank" rel="noopener">워니즈 깃헙</a>
<h2 class="wp-block-heading">함께 보면 좋은 글</h2>
<ul class="wp-block-list"><li><a href="https://blog.wonizz.com/2019/07/31/docker-dockerfile/">[Docker] Dockerfile 의 이해</a></li><li><a href="https://blog.wonizz.com/2019/07/27/docker-network/">[Docker] 네트워크의 이해</a></li><li><a href="https://blog.wonizz.com/2019/08/08/ansible-role-include/">[Ansible] 플레이북 Role 과 Include</a></li><li><a href="https://blog.wonizz.com/2019/08/13/docker-compose/">[Docker] Compose 구성과 사용법</a></li></ul>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/07/29/docker-volume/">[Docker] Volume 의 관리</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.wonizz.com/2019/07/29/docker-volume/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">636</post-id>	</item>
	</channel>
</rss>
