<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>container on LaMelD</title><link>https://lameld.github.io/tags/container/</link><description>Recent content in container on LaMelD</description><generator>Hugo</generator><language>ko-KR</language><lastBuildDate>Tue, 14 Jul 2020 00:00:00 +0000</lastBuildDate><atom:link href="https://lameld.github.io/tags/container/index.xml" rel="self" type="application/rss+xml"/><item><title>CH01. 도커의 기본</title><link>https://lameld.github.io/docker/ch-01/</link><pubDate>Wed, 01 Jul 2020 00:00:00 +0000</pubDate><guid>https://lameld.github.io/docker/ch-01/</guid><description>&lt;h2 id="1-도커란-무엇인가"&gt;1. 도커란 무엇인가?&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;도커&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너형 가상화 기술을 구현하기 위해 상주 어플리케이션과 이 어플리케이션을 조작하기 위한 명령행 도구로 구성되는 프로덕트다.&lt;/li&gt;&#10;&lt;li&gt;어플리케이션 배포에 특화되어 있기 때문에 어플리케이션 개발 및 운영을 컨테이너 중심으로 할 수 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;도커의 역사&lt;/p&gt;</description></item><item><title>CH02. 도커 컨테이너 배포</title><link>https://lameld.github.io/docker/ch-02/</link><pubDate>Wed, 01 Jul 2020 00:00:00 +0000</pubDate><guid>https://lameld.github.io/docker/ch-02/</guid><description>&lt;h2 id="1-컨테이너로-어플리케이션-실행하기"&gt;1. 컨테이너로 어플리케이션 실행하기&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;도커 이미지 : 도커 컨테이너를 구성하는 파일 시스템과 실행할 어플리케이션 설정을 하나로 합친 것으로 컨테이너를 생성하는 템플릿 역할을 한다.&lt;/p&gt;</description></item><item><title>CH03. 컨테이너 실전 구축 및 배포</title><link>https://lameld.github.io/docker/ch-03/</link><pubDate>Fri, 03 Jul 2020 00:00:00 +0000</pubDate><guid>https://lameld.github.io/docker/ch-03/</guid><description>&lt;h2 id="1-어플리케이션과-시스템-내-단일-컨테이너의-적정-비중"&gt;1. 어플리케이션과 시스템 내 단일 컨테이너의 적정 비중&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;header&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;도커를 사용해 시스템을 구축한다는 것 = 자신이 만든 어플 컨테이너 + 공개된 어플/미들웨어 컨테이너&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;컨테이너 1개 = 프로새스 1개?&lt;/p&gt;</description></item><item><title>CH04. 스웜을 이용한 실전 어플리케이션 개발</title><link>https://lameld.github.io/docker/ch-04/</link><pubDate>Wed, 01 Jul 2020 00:00:00 +0000</pubDate><guid>https://lameld.github.io/docker/ch-04/</guid><description>&lt;h2 id="1-웹-어플리케이션-구성"&gt;1. 웹 어플리케이션 구성&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;어플리케이션의 요구 조건&#10;&lt;ul&gt;&#10;&lt;li&gt;TODO를 등록, 수정, 삭제할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;등록된 TODO의 목록을 출력할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;브라우저에서 사용할 수 있는 웹 어플리케이션이다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;아키텍처&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;오케스트레이션 시스템은 도커 스웜 사용&lt;/p&gt;</description></item><item><title>CH05. 쿠버네티스 입문</title><link>https://lameld.github.io/docker/ch-05/</link><pubDate>Wed, 01 Jul 2020 00:00:00 +0000</pubDate><guid>https://lameld.github.io/docker/ch-05/</guid><description>&lt;h2 id="1-쿠버네티스란-무엇인가"&gt;1. 쿠버네티스란 무엇인가?&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;INTRO&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너 운영을 자동화하기 위한 컨테이너 오케스트레이션 도구( 구글의 주도로 개발되었다. )&lt;/li&gt;&#10;&lt;li&gt;컨테이너를 이용한 어플리케이션 배포할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;다양한 운영 관리 업무를 자동화할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;컨테이너 배치, 스케일링, 로드벨런싱, 헬스 체크 등 기능을 갖추고 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;도커의 부상과 쿠버네티스의 탄생&lt;/p&gt;</description></item><item><title>CH06. 쿠버네티스 클러스터 구축</title><link>https://lameld.github.io/docker/ch-06/</link><pubDate>Wed, 01 Jul 2020 00:00:00 +0000</pubDate><guid>https://lameld.github.io/docker/ch-06/</guid><description>&lt;h2 id="1-google-kubernetes-engine-환경-설정"&gt;1. Google Kubernetes Engine 환경 설정&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;4장에서 구축한 TODO 어플리케이션을 쿠버네티스로 전환하고 GKE를 사용해서 배포할 것이다.&lt;/p&gt;</description></item><item><title>CH07. 쿠버네티스 실전편</title><link>https://lameld.github.io/docker/ch-07/</link><pubDate>Wed, 01 Jul 2020 00:00:00 +0000</pubDate><guid>https://lameld.github.io/docker/ch-07/</guid><description>&lt;h2 id="1-쿠버네티스의-그-외-리소스"&gt;1. 쿠버네티스의 그 외 리소스&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;INTRO&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;쿠버네티스는 데몬으로 동작하는 서버 어플리케이션 외에도 배치 서버 등 다양한 형태의 어플리케이션을 구축할 수 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;잡(Job)&lt;/p&gt;</description></item><item><title>CH08. 컨테이너 운영</title><link>https://lameld.github.io/docker/ch-08/</link><pubDate>Wed, 01 Jul 2020 00:00:00 +0000</pubDate><guid>https://lameld.github.io/docker/ch-08/</guid><description>&lt;h2 id="1-로깅-운영"&gt;1. 로깅 운영&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;INTRO&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너 환경의 효율적인 로그 관리 등 관리 운영적 부분에 중접을 두고 운영 환경에서 알아둬야 할 주의 사항을 설명한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;컨테이너에서 생성되는 로그&#10;&lt;ul&gt;&#10;&lt;li&gt;비컨테이너 환경&#10;&lt;ul&gt;&#10;&lt;li&gt;서버 업타임이 길기 때문에 로그가 누적되어 상당한 디스크 용량을 차지하는 일이 자주 발생한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;도커&#10;&lt;ul&gt;&#10;&lt;li&gt;로그 라이브러리를 사용해도 로그가 파일이 아니라 표준 출력으로 출력하고 이를 다시 Fluentd 같은 로그 컬렉터로 수집하는 경우가 많다.&lt;/li&gt;&#10;&lt;li&gt;어플리케이션 쪽에서 로그 로테이션을 할 필요가 없으며 로그 전송을 돕는 로깅 드라이버 기능도 갖추고 있으므로 로그 수집이 편리하다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;표준 출력과 로그&#10;&lt;ul&gt;&#10;&lt;li&gt;gihyodocker/echo:latest 사용&lt;/li&gt;&#10;&lt;li&gt;포어그라운드로 실행한 다음 http://localhost:8080으로 요청을 보내면 표준 출력으로 출력된다.&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker container run -it --rm -p 8080:8080 gihyodocker/echo:latest&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2020/06/26 02:19:53 start server&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2020/06/26 02:20:18 received request&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;호스트에 컨테이너 데이터가 저장되는 디렉터리 : /var/lib/docker/containers/컨테이너ID&lt;/li&gt;&#10;&lt;li&gt;컨테이너 데이터가 저장되는 디렉터리에 컨테이너ID-json.log 파일이 로그 파일이다.&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 컨테이너ID : 9b0eb43784afcc61efb36de58c4115931a0fa51fb87629ee6cff8624e0dd999a&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;containers&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;컨테이너&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;컨테이너&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;또는&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 로그파일 있는 곳을 볼륨으로 컨테이너 생성&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt; &lt;span class="n"&gt;alpine&lt;/span&gt; &lt;span class="n"&gt;ash&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="c1"&gt;# cd json-log/[컨테이너ID]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;컨테이너&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="c1"&gt;# ls&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;컨테이너&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="c1"&gt;# tail [컨테이너ID]-json.log&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;컨테이너 표준 출력으로 출력된 내용이 JSON 포맷으로 출력된 것을 확인할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;어플리케이션에서 로그를 파일에 출력하도록 구현하지 않았더라도 도커에서 컨테이너의 표준 출력을 로그로 출력해 주는 것이다.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;로그 출력 자체를 완전히 도커에 맡길 수 있다.&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;로깅 드라이버&#10;&lt;ul&gt;&#10;&lt;li&gt;로그가 JSON 포맷으로 출력되는 이유는 도커에 json-file이라는 기본 로깅 드라이버가 있기 때문이다.&lt;/li&gt;&#10;&lt;li&gt;로깅 드라이버 : 도커 컨테이너가 출력하는 로그를 어떻게 다룰지를 제어하는 역할을 한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: left"&gt;종류&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: left"&gt;설명&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;Syslog&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;syslog로 로그를 관리&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;Journald&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;systemd로 로그를 관리&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;Awslogs&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;AWS CloudWatch Logs로 로그를 전송&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;Gcplogs&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;Google Cloud Logging으로 로그를 전송&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;Fluentd&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;fluentd로 로그를 관리&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;컨테이너 로그 다루기&#10;&lt;ul&gt;&#10;&lt;li&gt;장애로 인해 예기치 않게 컨테이너가 정지되고 디스크에서 완전히 삭제되었다면 컨테이너 안에 로그를 파일로 남기면 컨테이너를 삭제할 때 로그도 함께 잃어버린다는 큰 문제가 발생한다.&lt;/li&gt;&#10;&lt;li&gt;방법&#10;&lt;ul&gt;&#10;&lt;li&gt;호스트에서 컨테이너에 공유한 볼륨에 파일로 로그를 남기는 방법&lt;/li&gt;&#10;&lt;li&gt;로그를 표준 출력으로 남기고 이 내용을 호스트에서 파일에 수집하는 방법&lt;/li&gt;&#10;&lt;li&gt;도커에서는 후자를 정석으로 여긴다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;컨테이너 로그의 로테이션&#10;&lt;ul&gt;&#10;&lt;li&gt;도커 컨테이너 로깅 동작 제어 옵션 : &amp;ndash;log-opt&#10;&lt;ul&gt;&#10;&lt;li&gt;&amp;ndash;log-opt max-size=1m : 로테이션이 발생하는 로그 파일 최대 크기&lt;/li&gt;&#10;&lt;li&gt;&amp;ndash;log-opt max-file=5 : 최대 파일 개수. 이 값을 초과할 경우 오래된 파일부터 삭제된다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker container run -it --rm -p 8080:8080 --log-opt max-size=1m --log-opt max-file=5 gihyodocker/echo:latest&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;max-size로 설정한 파일 크기에 도달하면 파일이 로테이션된다.&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;----.log # 최신&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;----.log.1 # 이전 로그&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;이 설정은 컨테이너마다 일일이 할 필요는 없고, 도커 데몬에서 log-opts 기본값으로 설정할 수 있다.&#10;&lt;ul&gt;&#10;&lt;li&gt;/etc/docker/daemon.json&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;log-driver&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;json-file&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;log-opts&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;max-size&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;10m&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;max-file&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;5&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;Fluentd와 Elasticsearch를 이용한 로그 수집 및 검색 기능 구축&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;파일 기반의 로그 관리 방식은 번거롭다.&lt;/p&gt;</description></item><item><title>CH09. 가벼운 도커 이미지 만들기</title><link>https://lameld.github.io/docker/ch-09/</link><pubDate>Thu, 02 Jul 2020 00:00:00 +0000</pubDate><guid>https://lameld.github.io/docker/ch-09/</guid><description>&lt;ul&gt;&#10;&lt;li&gt;도커 이미지의 최적하 보다는 어플리케이션의 동작을 우선시했다.&lt;/li&gt;&#10;&lt;li&gt;일정 규모 이상의 어플리케이션을 본격적으로 구축하려면 도커 이미지 크기에도 신경 써야 한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="1-가벼운-도커-이미지가-왜-필요할까"&gt;1. 가벼운 도커 이미지가 왜 필요할까&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;이미지 크기 증가에 따라 나타는 문제&#10;&lt;ul&gt;&#10;&lt;li&gt;이미지 크기가 미치는 영향&#10;&lt;ul&gt;&#10;&lt;li&gt;이미지 빌드 시간(기반 이미지 다운로드 시간 포함)&lt;/li&gt;&#10;&lt;li&gt;이미지를 도커 레지스트리에 등록하는 시간&lt;/li&gt;&#10;&lt;li&gt;컨테이너를 실행할 호스트 혹은 노드에서 이미지를 다운로드하는 시간&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;나비효과&#10;&lt;ul&gt;&#10;&lt;li&gt;클러스터를 구성하는 노드의 디스크 용량 낭비&lt;/li&gt;&#10;&lt;li&gt;CI 소요 시간 증가&lt;/li&gt;&#10;&lt;li&gt;개발 중 시행착오 소요 시간 증가로 인한 생산성 저하&lt;/li&gt;&#10;&lt;li&gt;오토 스케일리으로 컨테이너가 투입되는 소요 시간 증가(노드에 이미지가 없는 경우 새로 받아와야 하므로)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;새 노드에 얼마나 빨리 도커 이미지를 배치할 수 있는가가 중요하다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="2-기반-이미지를-가볍게"&gt;2. 기반 이미지를 가볍게&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;scratch&#10;&lt;ul&gt;&#10;&lt;li&gt;INTRO&#10;&lt;ul&gt;&#10;&lt;li&gt;빈 도커 이미지로, 도커가 이름을 예약한 특수 이미지다.&lt;/li&gt;&#10;&lt;li&gt;Dockerfile의 FROM 인스트럭션에서 참조만 가능하다.&lt;/li&gt;&#10;&lt;li&gt;컨테이너 외부로부터 파일을 주입받은 후에야 실체를 갖게 된다.&lt;/li&gt;&#10;&lt;li&gt;현재 존재하는 모든 도커 이미지의 기반 이미지를 따라가 보면 결국 이 scratch 이미지에 이르게 된다.&lt;/li&gt;&#10;&lt;li&gt;scratch 이미지는 모든 이미지의 조상 격이다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;scratch 이미지로 만든 이미지 빌드 들여다보기&#10;&lt;ul&gt;&#10;&lt;li&gt;ubuntu:trusty 이미지의 Dockerfile&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-Dockerfile" data-lang="Dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;scratch&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt; ubuntu-trusty-core-cloudimg-amd64-root.tar.gz /&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; -xe &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#!/bin/sh&amp;#39;&lt;/span&gt; &amp;gt; /usr/sbin/policy-rc.d &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;exit 101&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; /usr/sbin/policy-rc.d &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; chmod +x /usr/sbin/policy-rc.d &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; dpkg-divert --local --rename --add /sbin/initctl &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cp -a /usr/sbin/policy-rc.d /sbin/initctl &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; sed -i &lt;span class="s1"&gt;&amp;#39;s/^exit.*/exit 0/&amp;#39;&lt;/span&gt; /sbin/initctl &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;force-unsafe-io&amp;#39;&lt;/span&gt; &amp;gt; /etc/dpkg/dpkg.cfg.d/docker-apt-speedup &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DPkg::Post-Invoke { &amp;#34;rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true&amp;#34;; };&amp;#39;&lt;/span&gt; &amp;gt; /etc/apt/apt.conf.d/docker-clean &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;APT::Update::Post-Invoke { &amp;#34;rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial*.deb /var/cache/apt/*.bin || true&amp;#34;; };&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/apt.conf.d/docker-clean &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Dir::Cache::pkgcache &amp;#34;&amp;#34;; Dir::Cache::srcpkgcache &amp;#34;&amp;#34;;&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/apt.conf.d/docker-clean &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Acquire::Languages &amp;#34;none&amp;#34;;&amp;#39;&lt;/span&gt; &amp;gt; /etc/apt/apt.conf.d/docker-no-languages &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Acquire::GzipIndexes &amp;#34;true&amp;#34;; Acquire::CompressionTypes::Order:: &amp;#34;gz&amp;#34;;&amp;#39;&lt;/span&gt; &amp;gt; /etc/apt/apt.conf.d/docker-gzip-indexes &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Apt::AutoRemove::SuggestsImportant &amp;#34;false&amp;#34;;&amp;#39;&lt;/span&gt; &amp;gt; /etc/apt/apt.conf.d/docker-autoremove-suggests&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; rm -rf /var/lib/apt/lists/*&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; sed -i &lt;span class="s1"&gt;&amp;#39;s/^#\s*\(deb.*universe\)$/\1/g&amp;#39;&lt;/span&gt; /etc/apt/sources.list&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CMD&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/bin/bash&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;ubuntu-trusty-core-cloudimg-amd64-root.tar.gz : 우분투 운영체제를 구성하는 최소한의 파일을 디렉토리 구조 그대로 압축한 것&lt;/li&gt;&#10;&lt;li&gt;ADD 인스트럭션은 COPY와 다르게 압축해제 기능이 있다.&lt;/li&gt;&#10;&lt;li&gt;CMD 인스트럭션에 /bin/bash 명령을 지정하여 컨테이너가 /bin/bash를 포어그라운드로 실행하므로 우분투 서버 자체가 상주 형태로 실행되는 것처럼 보인다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;어플리케이션을 실행하는데 운영 체제를 구성하는 파일을 모두 사용하는 것은 아니기 때문에 대부분의 파일은 쓸모없이 이미지의 용량만 차지한다.&lt;/li&gt;&#10;&lt;li&gt;간단한 이미지 만들기&#10;&lt;ul&gt;&#10;&lt;li&gt;hello.go 작성&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-golang" data-lang="golang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello, scratch!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;바이너리를 복사할 수 있도록 컨테이너 밖에서 컴파일한다.&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ GOOS=linux GOARCH=amd64 go build hello.go&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;Dockerfile 작성&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-Dockerfile" data-lang="Dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;scratch&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; hello /&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CMD&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;이미지 빌드&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker image build ch09/hello:latest .&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;컨테이너 실행&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker container run -t ch09/hello:latest&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;이미지 크기 확인&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker image ls | grep hello&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;프로그래밍 언어로 된 어플리케이션은 언어 런타임이나 라이브러리 등을 이미지에 포함해야 하므로 Go 언어에 비해서 이미지가 커지는 경향이 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;네이티브 라이브러리 링크&#10;&lt;ul&gt;&#10;&lt;li&gt;C언어나 Go 언어에서 빌드한 실행 바이너리를 컨테이너에 복사하기만 하면 된다.&lt;/li&gt;&#10;&lt;li&gt;어플리케이션이 동적 링크를 사용하는 경우 주의해야 한다.&lt;/li&gt;&#10;&lt;li&gt;빌드시 네이티브 의존 라이브러리를 정적 링크하도록 하면 이미지를 만드는 수고를 크게 덜 수 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;루트 인증서&#10;&lt;ul&gt;&#10;&lt;li&gt;TLS/SSL이 적용된 웹 사이트에 접근&lt;/li&gt;&#10;&lt;li&gt;hello.go 수정&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-golang" data-lang="golang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;io/ioutil&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello, scratch!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;https://gihyo.jp/&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ioutil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;이 어플리케이션을 빌드하고 컨테이너로 실행하면 인증서 오류가 발생한다.&lt;/li&gt;&#10;&lt;li&gt;TLS/SSL이 적용된 HTTPS 웹 사이트에 접근하려면 루트 인증서가 필요하다.&lt;/li&gt;&#10;&lt;li&gt;일반적인 운영체제라면 루트 인증서가 포함되지만 scratch 이미지에는 루트 인증서 자체가 없기 때문에 오류가 발생한다.&lt;/li&gt;&#10;&lt;li&gt;Dockerfile 수정&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-Dockerfile" data-lang="Dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;scratch&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; hello /&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; cacert.pem /etc/ssl/certs/&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CMD&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;운영 체제가 포함된 이미지라면 패키지 관리자를 통해 필요한 라이브러리나 도구를 추가할 수 있지만 scratch 이미지에는 패키지 관리자 같은 것이 존재하지 않는다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;scratch 이미지의 실용성&#10;&lt;ul&gt;&#10;&lt;li&gt;scratch 이미지에서 동작하려면 빌드부터 시작해야 하는 것은 물론, 다양한 의존 모듈이 필요하다.&lt;/li&gt;&#10;&lt;li&gt;디버그를 하려고 해도 셸이 없기 때문에 컨테이너 안의 상황을 파악하기가 어렵다.&lt;/li&gt;&#10;&lt;li&gt;이 점은 이미지의 크기와 트레이드 오프 관계를 가지므로 이러한 부분을 포기하더라도 작은 이미지가 필요한 상황이라면 scratch도 선택지에 포함시킬 수 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;busybox&#10;&lt;ul&gt;&#10;&lt;li&gt;INTRO&#10;&lt;ul&gt;&#10;&lt;li&gt;busybox는 임베디드 시스템에서 많이 사용하는 리눅스 배포판이다.&lt;/li&gt;&#10;&lt;li&gt;busybox는 수백 종 이상의 기본 유틸리티를 갖추고 있다.&lt;/li&gt;&#10;&lt;li&gt;일반적인 운영 체제와 달리, 단일 바이너리 파일(/bin/busybox)에 모든 유틸리티가 포함된 형태다.&lt;/li&gt;&#10;&lt;li&gt;모든 명령어 파일이 /bin/busybox로 하드 링킹되어 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;표준 C 라이브러별 이미지&#10;&lt;ul&gt;&#10;&lt;li&gt;glibc&#10;&lt;ul&gt;&#10;&lt;li&gt;GNU C 라이브러리를 의미한다.&lt;/li&gt;&#10;&lt;li&gt;다양한 스펙 및 독자적인 확장 기능을 제공하기 때문에 유연하지만 그만큼 라이브러리 크기가 크다.&lt;/li&gt;&#10;&lt;li&gt;잘 사용하지 않는 기능 때문에 디스크 용량을 낭비한다는 문제가 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;uclibc&#10;&lt;ul&gt;&#10;&lt;li&gt;임베디드 환경에 특화된 가벼운 라이브러리로 추린 것이다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;musl&#10;&lt;ul&gt;&#10;&lt;li&gt;musl은 정적 링크에 최적화되어 있어 어플리케이션을 이동에 유리한 단일 바이너리로 빌드하기에 좋다.&lt;/li&gt;&#10;&lt;li&gt;POSIX 표준을 더 충실히 구현한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;아키텍처나 운영 체제가 다른 환경에서 glibc로 빌드한 바이너리는 uClibc나 musl을 사용한 컨테이너에서 실행이 되지 않는다.&lt;/li&gt;&#10;&lt;li&gt;빌드 환경과 실행 환경의 차이를 배제하기 위해 -glibc, -uclibc, -musl과 같은 라이브러리별 이미지를 제공한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;busybox의 실용성&#10;&lt;ul&gt;&#10;&lt;li&gt;최소한의 운영 체제 기능을 제공하면서도 운영 체제로 인한 이미지 크기 증가는 거의 제로에 가깝게 줄여준다.&lt;/li&gt;&#10;&lt;li&gt;busybox를 포함한 이미지는 scratch로 만든 이미지보다 1MB 정도 크기가 크지만, 셸을 포함하고 있어 컨테이너 안에서 디버깅 작업이 가능하다.&lt;/li&gt;&#10;&lt;li&gt;에이전트 타입 어플리케이션이나 명령행 도구를 사용하는데 사용할 수 있다.(scratch와 마찬가지로)&lt;/li&gt;&#10;&lt;li&gt;패키지 관리자가 없다.&lt;/li&gt;&#10;&lt;li&gt;이미지 크기에 구애받지 않거나 이미지 빌드가 까다로운 경우에는 우분투나 CentOS 등의 이미지를 사용하는 것이 편리하다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;alpine&#10;&lt;ul&gt;&#10;&lt;li&gt;INTRO&#10;&lt;ul&gt;&#10;&lt;li&gt;busybox를 기반으로 한 리눅스 배포판으로 &amp;lsquo;보안, 간결함, 리소스 효율을 중시하는 파워 유저&amp;rsquo;를 대상으로 설계했으며, 표준 C 라이브러리 구현체 중 musl을 사용한다.&lt;/li&gt;&#10;&lt;li&gt;리눅스 배포판의 표준이라고 할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;패키지 관리자인 apk를 사용할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;Dockerfile의 내용이 너무 장황하거나 이미지 빌드에 필요한 사전 준비가 지나치게 늘어나면 이미지 전체 내용을 파악하기 어려워진다. 이런 문제를 해결하려면 쓸 만한 패키지 관리자가 반드시 필요하다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;alpine 컨테이너 실행하기&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker container run -it alpine:3.7 sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;패키지 관리자 apk 사용법&#10;&lt;ul&gt;&#10;&lt;li&gt;apk의 패키지 리포지토리가 중앙 집권적이라는 특징이 있다.&lt;/li&gt;&#10;&lt;li&gt;apk update : 로컬에 캐싱된 apk 패키지 인덱스를 업데이트하는 명령.&lt;/li&gt;&#10;&lt;li&gt;apk search : 현재 사용할 수 있는 패키지를 검색하는 명령.&lt;/li&gt;&#10;&lt;li&gt;apk add : 패키지를 설치하는 명령.&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;--no-cache&lt;/code&gt; 옵션&#10;&lt;ul&gt;&#10;&lt;li&gt;/var/cache/apk 디렉터리에 저장된 apk 인덱스 대신 새로 받아온 인덱스 정보를 이용해 패키지를 설치한다.&lt;/li&gt;&#10;&lt;li&gt;/var/cache/apk 디렉터리에 캐시를 저장하지 않으므로 이 디렉터리의 내용을 따로 삭제할 필요도 없다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;--virtual&lt;/code&gt; 옵션&#10;&lt;ul&gt;&#10;&lt;li&gt;여러 패키지를 합쳐 하나의 별명을 붙이는 기능을 제공한다.&lt;/li&gt;&#10;&lt;li&gt;빌드 시에만 필요한 이미지를 그대로 남겨두면 이미지 크기가 불필요하게 증가할 수 있으므로 이 라이브러리를 제거하는 것이 좋다.&lt;/li&gt;&#10;&lt;li&gt;불필요한 패키지를 한번에 제거할 수 있다.(&lt;code&gt;apk del [별명]&lt;/code&gt;)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;apk del : 설치된 패키지를 제거하는 명령&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;알파인 리눅스 기반 도커 이미지 만들기&#10;&lt;ul&gt;&#10;&lt;li&gt;2장의 echo를 사용한다.&lt;/li&gt;&#10;&lt;li&gt;main.go&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;log&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;start server&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;:8080&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;/&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;received request&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello Docker!!!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;Dockerfile&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-Dockerfile" data-lang="Dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;alpine:3.7&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# (0) workspace 등록 및 환경 변수 등록&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WORKDIR /&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ENV&lt;/span&gt; GOPATH /go&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# (1) 빌드 시에만 필요한 라이브리 및 도구 설치&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; apk add --no-cache --virtual&lt;span class="o"&gt;=&lt;/span&gt;build-devs go git gcc g++&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# (2) 실행 시에도 필요한 라이브리 및 도구 설치&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; apk add --no-cache ca-certificates&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# (3) echo를 빌드해 실행 파일을 만듬&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; . /go/src/github.com/lameld/echo&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; /go/src/github.com/lameld/echo &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; go build -o bin/echo main.go&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; /go/src/github.com/lameld/echo &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cp bin/echo /usr/local/bin/&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# (4) 빌드 시에만 필요한 라이브러리 및 도구 제거&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; apk del --no-cache build-devs&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CMD&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;echo&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;이미지 빌드&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker image build -t ch09/echo:latest .&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="3-가벼운-도커-이미지-만들기"&gt;3. 가벼운 도커 이미지 만들기&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;배포 대상 어플리케이션 크기 줄이기&#10;&lt;ul&gt;&#10;&lt;li&gt;어플리케이션 크기 최적화&#10;&lt;ul&gt;&#10;&lt;li&gt;불필요한 파일 삭제&lt;/li&gt;&#10;&lt;li&gt;불필요한 프로그램 최소화&lt;/li&gt;&#10;&lt;li&gt;의존 라이브러리 최소화&lt;/li&gt;&#10;&lt;li&gt;웹 어플리케이션의 애셋(주로 이미지) 용량 줄이기&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;.dockerignore 파일&#10;&lt;ul&gt;&#10;&lt;li&gt;불필요한 파일 및 디렉터리가 컨텡너에 들어가지 않게 하는 것이 중요하다.&lt;/li&gt;&#10;&lt;li&gt;.git 디렉토리로 대표되는 불필요함 숨김 파일이 컨테이너에 들어가기 쉽다.&lt;/li&gt;&#10;&lt;li&gt;Dockerfile과 같은 디렉토리에에 위치차 .dockerignore 파일에 컨테이너 포함하지 않을 파일이나 디렉토리를 정의하는 기능이다.&lt;/li&gt;&#10;&lt;li&gt;.dockerignore&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;.git&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;.idea&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;*.swp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;*.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;.DS_STORE&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;도커 이미지의 레이어 구조 고려하기&#10;&lt;ul&gt;&#10;&lt;li&gt;INTRO&#10;&lt;ul&gt;&#10;&lt;li&gt;이미지의 크기를 최적화하려면 이 내부 구조까지 깊이 이해할 필요가 있다.&lt;/li&gt;&#10;&lt;li&gt;echo 이미지를 빌드해 보면 다음과 같은 내용이 출력된다.&lt;/li&gt;&#10;&lt;li&gt;각 단계별로 Dockerfile에 기술된 명령이 실행되는 것을 알 수 있다.&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker image build -t ch09/echo:latest .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Sending build context to Docker daemon 3.072kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 1/10 : FROM alpine:3.7&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 6d1ef012b567&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 2/10 : WORKDIR /&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; Using cache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 96f74ddcf3b7&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 3/10 : ENV GOPATH /go&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; Using cache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; acaeee72e27d&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 4/10 : RUN apk add --no-cache --virtual=build-devs go git gcc g++&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; Using cache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; fa4f43acbc98&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 5/10 : RUN apk add --no-cache ca-certificates&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; Using cache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 1ad9964de84c&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 6/10 : COPY . /go/src/github.com/lameld/echo&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; Using cache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; f84186eefbc7&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 7/10 : RUN cd /go/src/github.com/lameld/echo &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; go build -o bin/echo main.go&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; Using cache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 77ffccfd40f7&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 8/10 : RUN cd /go/src/github.com/lameld/echo &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cp bin/echo /usr/local/bin/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; Using cache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 56242e05b9ce&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 9/10 : RUN apk del --no-cache build-devs&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; Using cache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 9d06ac4d82e2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 10/10 : CMD [&lt;span class="s2"&gt;&amp;#34;echo&amp;#34;&lt;/span&gt;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; Using cache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 7bce58ed9dea&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Successfully built 7bce58ed9dea&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Successfully tagged ch09/echo:latest&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;해당 이미지가 어떤 레이어로 구성되었는지 자세한 정보 보기 : &lt;code&gt;docker image history&lt;/code&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker image history ch09/echo:latest&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;IMAGE CREATED CREATED BY SIZE COMMENT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;7bce58ed9dea 2 minutes ago /bin/sh -c #(nop) CMD [&amp;#34;echo&amp;#34;] 0B &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;9d06ac4d82e2 2 minutes ago /bin/sh -c apk del --no-cache build-devs 34kB &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;56242e05b9ce 2 minutes ago /bin/sh -c cd /go/src/github.com/lameld/echo… 7.52MB &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;77ffccfd40f7 2 minutes ago /bin/sh -c cd /go/src/github.com/lameld/echo… 7.52MB &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;f84186eefbc7 2 minutes ago /bin/sh -c #(nop) COPY dir:afb826e60552ed0da… 713B &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1ad9964de84c 2 minutes ago /bin/sh -c apk add --no-cache ca-certificates 515kB &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fa4f43acbc98 2 minutes ago /bin/sh -c apk add --no-cache --virtual=buil… 359MB &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;acaeee72e27d 3 minutes ago /bin/sh -c #(nop) ENV GOPATH=/go 0B &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;96f74ddcf3b7 3 minutes ago /bin/sh -c #(nop) WORKDIR / 0B &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;6d1ef012b567 16 months ago /bin/sh -c #(nop) CMD [&amp;#34;/bin/sh&amp;#34;] 0B &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;missing&amp;gt; 16 months ago /bin/sh -c #(nop) ADD file:aa17928040e31624c… 4.21MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;각 레이어에 해당하는 이미지는 도커 파일 시스템 안에 tar.gz 파일에 저장된다.&lt;/li&gt;&#10;&lt;li&gt;레이어 자체도 이미지이며, 중간 과정에 특정한 태그를 붙일 수 있다.&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker image tag f84186eefbc7 ch09/echo:copy&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;레이어의 수를 최대한 줄이기&#10;&lt;ul&gt;&#10;&lt;li&gt;이미지를 구성하는 레이어 자체도 이미지 파일 형태로 디스크에 존재한다.&lt;/li&gt;&#10;&lt;li&gt;때문에 빌드 중에 필요했던 파일도 최종 결과물이 될 이미지에서 불필요한 파일이라면 결국 최종 이미지에 불필요한 파일에 들어간다.&lt;/li&gt;&#10;&lt;li&gt;entrykit 이미지&#10;&lt;ul&gt;&#10;&lt;li&gt;Dockerfile&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-Dockerfile" data-lang="Dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;alpine:3.7&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; apk add --no-cache wget&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; wget https://github.com/progrium/entrykit/releases/download/v0.4.0/entrykit_0.4.0_Linux_x86_64.tgz&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; tar -xvzf entrykit_0.4.0_Linux_x86_64.tgz&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; rm entrykit_0.4.0_Linux_x86_64.tgz&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; mv entrykit /bin/entrykit&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; chmod +x /bin/entrykit&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; entrykit --symlink&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;이미지 빌드&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="n"&gt;ch09&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;entrykit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;standard&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Sending&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;Docker&lt;/span&gt; &lt;span class="n"&gt;daemon&lt;/span&gt; &lt;span class="mf"&gt;2.048&lt;/span&gt;&lt;span class="n"&gt;kB&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;alpine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;3.7&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="n"&gt;d1ef012b567&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RUN&lt;/span&gt; &lt;span class="n"&gt;apk&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;no&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="n"&gt;wget&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Using&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="n"&gt;ddb2b2b256e&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RUN&lt;/span&gt; &lt;span class="n"&gt;wget&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;progrium&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;entrykit&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;releases&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;4.0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;entrykit_0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;4.0&lt;/span&gt;&lt;span class="n"&gt;_Linux_x86_64&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tgz&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Using&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bbb9cf07b1a2&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RUN&lt;/span&gt; &lt;span class="n"&gt;tar&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;xvzf&lt;/span&gt; &lt;span class="n"&gt;entrykit_0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;4.0&lt;/span&gt;&lt;span class="n"&gt;_Linux_x86_64&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tgz&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Using&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="n"&gt;ed24750e29&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RUN&lt;/span&gt; &lt;span class="n"&gt;rm&lt;/span&gt; &lt;span class="n"&gt;entrykit_0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;4.0&lt;/span&gt;&lt;span class="n"&gt;_Linux_x86_64&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tgz&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Using&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;063&lt;/span&gt;&lt;span class="n"&gt;c338b89b0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RUN&lt;/span&gt; &lt;span class="n"&gt;mv&lt;/span&gt; &lt;span class="n"&gt;entrykit&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;entrykit&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Using&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="n"&gt;ae51cb1f1b&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RUN&lt;/span&gt; &lt;span class="n"&gt;chmod&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;entrykit&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Using&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dbfc1a91f15f&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RUN&lt;/span&gt; &lt;span class="n"&gt;entrykit&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;symlink&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Using&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;5e6&lt;/span&gt;&lt;span class="n"&gt;c02d2e7c0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Successfully&lt;/span&gt; &lt;span class="n"&gt;built&lt;/span&gt; &lt;span class="mf"&gt;5e6&lt;/span&gt;&lt;span class="n"&gt;c02d2e7c0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Successfully&lt;/span&gt; &lt;span class="n"&gt;tagged&lt;/span&gt; &lt;span class="n"&gt;ch09&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;entrykit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;standard&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;이미지 레이어&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker image history ch09/entrykit:standard&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;IMAGE CREATED CREATED BY SIZE COMMENT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;5e6c02d2e7c0 5 minutes ago /bin/sh -c entrykit --symlink 32B &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dbfc1a91f15f 5 minutes ago /bin/sh -c chmod +x /bin/entrykit 9.19MB &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;13ae51cb1f1b 5 minutes ago /bin/sh -c mv entrykit /bin/entrykit 9.19MB &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;063c338b89b0 5 minutes ago /bin/sh -c rm entrykit_0.4.0_Linux_x86_64.tgz 0B &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;72ed24750e29 5 minutes ago /bin/sh -c tar -xvzf entrykit_0.4.0_Linux_x8… 9.19MB &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bbb9cf07b1a2 5 minutes ago /bin/sh -c wget https://github.com/progrium/… 2.71MB &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;9ddb2b2b256e 6 minutes ago /bin/sh -c apk add --no-cache wget 480kB &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;6d1ef012b567 16 months ago /bin/sh -c #(nop) CMD [&amp;#34;/bin/sh&amp;#34;] 0B &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;missing&amp;gt; 16 months ago /bin/sh -c #(nop) ADD file:aa17928040e31624c… 4.21MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;각 레이어에서 파일을 조작할 때마다 최종 이미지의 크기가 증가함을 알 수 있다.&lt;/li&gt;&#10;&lt;li&gt;이런 현상을 피하려면 Dockerfile을 빌드 해 생성되는 이미지의 레이어 수를 줄이는 것이 가장 효과적이다.&lt;/li&gt;&#10;&lt;li&gt;Dockerfile.light&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-Dockerfile" data-lang="Dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;alpine:3.7&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; apk add --no-cache wget &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wget https://github.com/progrium/entrykit/releases/download/v0.4.0/entrykit_0.4.0_Linux_x86_64.tgz &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tar -xvzf entrykit_0.4.0_Linux_x86_64.tgz &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm entrykit_0.4.0_Linux_x86_64.tgz &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mv entrykit /bin/entrykit &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod +x /bin/entrykit &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;entrykit --symlink&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;이미지 빌드&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="n"&gt;built&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="n"&gt;Dockerfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;light&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="n"&gt;ch09&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;entrykit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;light&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Sending&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;Docker&lt;/span&gt; &lt;span class="n"&gt;daemon&lt;/span&gt; &lt;span class="mf"&gt;3.072&lt;/span&gt;&lt;span class="n"&gt;kB&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;alpine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;3.7&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="n"&gt;d1ef012b567&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Step&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RUN&lt;/span&gt; &lt;span class="n"&gt;apk&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;no&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="n"&gt;wget&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;wget&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;progrium&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;entrykit&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;releases&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;4.0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;entrykit_0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;4.0&lt;/span&gt;&lt;span class="n"&gt;_Linux_x86_64&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tgz&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;tar&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;xvzf&lt;/span&gt; &lt;span class="n"&gt;entrykit_0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;4.0&lt;/span&gt;&lt;span class="n"&gt;_Linux_x86_64&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tgz&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;rm&lt;/span&gt; &lt;span class="n"&gt;entrykit_0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;4.0&lt;/span&gt;&lt;span class="n"&gt;_Linux_x86_64&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tgz&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;mv&lt;/span&gt; &lt;span class="n"&gt;entrykit&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;entrykit&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;chmod&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;entrykit&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;entrykit&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;symlink&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Using&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;---&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b504a789d31f&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Successfully&lt;/span&gt; &lt;span class="n"&gt;built&lt;/span&gt; &lt;span class="n"&gt;b504a789d31f&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Successfully&lt;/span&gt; &lt;span class="n"&gt;tagged&lt;/span&gt; &lt;span class="n"&gt;ch09&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;entrykit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;light&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;이미지 레이어&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker image history ch09/entrykit:light&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;IMAGE CREATED CREATED BY SIZE COMMENT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;b504a789d31f About a minute ago /bin/sh -c apk add --no-cache wget &amp;amp;&amp;amp; wget h… 9.67MB &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;6d1ef012b567 16 months ago /bin/sh -c #(nop) CMD [&amp;#34;/bin/sh&amp;#34;] 0B &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;missing&amp;gt; 16 months ago /bin/sh -c #(nop) ADD file:aa17928040e31624c… 4.21MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;가독성과 이미지의 트레이드 오프&#10;&lt;ul&gt;&#10;&lt;li&gt;&amp;amp;&amp;amp;나 백슬래시를 만힝 사용해야 하며 빌드 스타일에 따라 cd 명령을 자주 사용하게 되므로 Dockerfile의 가독성을 해치게 된다.&lt;/li&gt;&#10;&lt;li&gt;이미지 빌드를 시행착오와 함께 반복해야 하는 경우라면 중간 빌드를 재활용하는 이점을 누릴 수가 없다.&lt;/li&gt;&#10;&lt;li&gt;이는 불가피하게 개발 효율을 떨어뜨리므로 개발 과정에서는 각 명령을 별도로 RUN 인스트럭션으로 실행한다.&lt;/li&gt;&#10;&lt;li&gt;빌드 내용이 고정된 다음에 RUN 인스트럭션의 실행 횟수를 줄이면 된다.&lt;/li&gt;&#10;&lt;li&gt;무리하게 모든 경우에 적용하지 않는 것이 좋다.&lt;/li&gt;&#10;&lt;li&gt;이 방법이 유용한 경우는 수 MB 이상의 파일으 자주 다루는 과정이 빌드에 포함되는 경우다.&lt;/li&gt;&#10;&lt;li&gt;중간 레이어 개수 자체가 적은 경우에는 굳이 적용할 필요가 없다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="4-멀티-스테이지-빌드"&gt;4. 멀티 스테이지 빌드&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;빌드 부산물을 완전히 제가할 수 없다는 한계의 대책 : 멀티 스테이지 빌드&lt;/li&gt;&#10;&lt;li&gt;빌드 컨테이너와 실행 컨테이너의 분리&#10;&lt;ul&gt;&#10;&lt;li&gt;적용 전&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-Dockerfile" data-lang="Dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;golang:1.13&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WORKDIR /&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ENV&lt;/span&gt; GOPATH /go&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; . /go/src/github.com/gihyodocker/todoapi&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; go get github.com/go-sql-driver/mysql&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; go get gopkg.in/gorp.v1&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; /go/src/github.com/gihyodocker/todoapi &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; go build -o bin/todoapi cmd/main.go&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; /go/src/github.com/gihyodocker/todoapi &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cp bin/todoapi /usr/local/bin/&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CMD&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;todoapi&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;적용 후&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-Dockerfile" data-lang="Dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;golang:1.13&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WORKDIR /&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ENV&lt;/span&gt; GOPATH /go&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; . /go/src/github.com/gihyodocker/todoapi&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; go get github.com/go-sql-driver/mysql&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; go get gopkg.in/gorp.v1&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; /go/src/github.com/gihyodocker/todoapi &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; go build -o bin/todoapi cmd/main.go&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;apline:3.7&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; --from&lt;span class="o"&gt;=&lt;/span&gt;build /go/src/github.com/gihyodocker/todoapi &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; cp bin/todoapi /usr/local/bin/&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CMD&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;todoapi&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;빌드 산출물을 다른 컨테이너로 복사할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;실행 컨테이너에 불필요한 파일을 전혀 포함하지 않고 가벼운 이미지를 만들 수 있다.&lt;/li&gt;&#10;&lt;li&gt;Dockerfile의 가독성을 유지하면서도 이미지의 크기를 억제할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;장점&#10;&lt;ul&gt;&#10;&lt;li&gt;이미지 크기 감소뿐만 아니라 이식성에도 도움을 준다.&lt;/li&gt;&#10;&lt;li&gt;하나의 Dockerfile 안에서 컨테이너 간에 파일을 주고 받기 때문에 도커 호스트와 상관 없이 항상 같은 최종 결과물을 얻을 수 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;</description></item><item><title>CH10. 다양한 도커 활용 방법</title><link>https://lameld.github.io/docker/ch-10/</link><pubDate>Fri, 03 Jul 2020 00:00:00 +0000</pubDate><guid>https://lameld.github.io/docker/ch-10/</guid><description>&lt;ul&gt;&#10;&lt;li&gt;팀 개발에서 개발환경을 통일&lt;/li&gt;&#10;&lt;li&gt;명령행 도구를 통한 도커 컨테이너 사용법&lt;/li&gt;&#10;&lt;li&gt;도커를 이용한 부하 테스트 방법&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="1-팀-개발에서-개발-환경-통일하기"&gt;1. 팀 개발에서 개발 환경 통일하기&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;INTRO&#10;&lt;ul&gt;&#10;&lt;li&gt;어플리케이션 및 미들웨어의 동작을 환경 변수로 제어하는 방법으로 도커 이미지의 추상 수준을 높일 수 있다.&lt;/li&gt;&#10;&lt;li&gt;다양한 환경에 배포하기 쉽게 할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;개발 환경을 공유하고 통일하는 방법으로 이용할 수 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;소프트웨어 및 도구 통일&#10;&lt;ul&gt;&#10;&lt;li&gt;호스에서 격리된 환경에 필요한 도구를 갖춘 도커 컨테이너를 공통 개발 환경으로 사용하는 것이 바람직하다.&lt;/li&gt;&#10;&lt;li&gt;예시&#10;&lt;ul&gt;&#10;&lt;li&gt;MySQL이나 Redis 같은 데이터스토어를 사용한는 프로젝트는 이 외 데이터스토어를 조작하기 위한 클라이언트 도구가 필요하다.&lt;/li&gt;&#10;&lt;li&gt;고성능 MySQL 클라이언트인 mycli 혹은 Redis 클라이언트인 redis-tools를 팀의 표준 도구로 지정하면 다음과 같은 도커 이미지를 공통 개발 환경으로 사용할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;Dockerfile&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-Dockerfile" data-lang="Dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ubuntu:16.04&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; apt -y update&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; apt -y install net-tools &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;iproute2 &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;inetutils-ping &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tcpdump &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mycli &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;redis-tools&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;이미지 빌드 및 컨테이너 생성(docker)&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker image build -t ch10/workspace:latest .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker container run --rm -it --name workspace ch10/workspace:latest bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;쿠버네티스에서 workspace 생성&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl run -i --rm --tty workspace --image=ch10/workspace:latest --restart=Never -- bash -il&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&amp;lsquo;하나의 컨테이너에 하나의 관심사&amp;rsquo;라는 도커의 원칙에는 어긋나지만, 어플리케이션 배포 용도가 아니므로 괜찮다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;개발 환경은 집단지성의 결과&#10;&lt;ul&gt;&#10;&lt;li&gt;팀 내 표준 개발 환경을 도커 컨테이너 형태로 제공하는 것은 매우 의미 있는 일이다.&lt;/li&gt;&#10;&lt;li&gt;장점&#10;&lt;ul&gt;&#10;&lt;li&gt;일단 개발 환경을 공유하면 여러 개발자가 수고를 덜 수 있다.&lt;/li&gt;&#10;&lt;li&gt;각자가 가진 노하우를 공유하고 이렇게 형성한 집단지성을 업무에 활용이 가능하다.&lt;/li&gt;&#10;&lt;li&gt;환경 구성 절차를 Dockerfile 형태의 프로그램으로 작성할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;신속하게 컨테이너를 실행하고 폐기할 수 있기 때문에 개발 환경에 베스트 프랙티스를 지속해서 반영할 수 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="2-도커-컨테이너에서-명령행-도구cli-사용하기"&gt;2. 도커 컨테이너에서 명령행 도구(CLI) 사용하기&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Dockerfile의 문법 검사를 도와주는 명령행 도구인 hadolint를 도커 컨테이너 형태로 실행한다.&#10;&lt;ul&gt;&#10;&lt;li&gt;Dockerfile&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;FROM alpine&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;RUN echo &amp;#34;docker!!&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;검사&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker container run --rm -i hadolint/hadolint &amp;lt; Dockerfile&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/dev/stdin:1 DL3006 Always tag the version of an image explicitly&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;이미지 버전 생략의 경고인 DL3006이 발생했다.&lt;/li&gt;&#10;&lt;li&gt;hadolint와 같은 도구를 처음 사용하더라도 추가적인 수고는 들지 않는다.&lt;/li&gt;&#10;&lt;li&gt;-i 옵션 : Dockerfile을 리다이렉트로 전달하기 위해서 사용하였다.&lt;/li&gt;&#10;&lt;li&gt;-v 옵션이 자주 같이 사용된다.&lt;/li&gt;&#10;&lt;li&gt;명령행 도구도 호스트에 설치하지 않고 도커 컨테이너 형태로 사용할 수 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;이미지에서 명령행 도구 버전 변경하기&#10;&lt;ul&gt;&#10;&lt;li&gt;명령행 도구를 사용할 때 중요함 점이 도구의 버전을 관리하는 것이다.&lt;/li&gt;&#10;&lt;li&gt;명령행 도구를 편리하게 사용하려면도구 버전을 업데이트하거나 특정 버전으로 고정하는 작업이 꼭 필요하다.&lt;/li&gt;&#10;&lt;li&gt;명령행 도구를 사용하면서 다음과 같은 필요가 발생할 수 있다.&#10;&lt;ul&gt;&#10;&lt;li&gt;항상 최신 버전(보안 패치가 모두 적용된)을 사용할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;버전이 바뀔 때마다 변경 사항이 많은 도구라서 특정 버전을 고정적으로 사용하고 싶다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;명령해 도구의 도커 이미지를 버전 별로 만들어 두는 것이 좋다.&#10;&lt;ul&gt;&#10;&lt;li&gt;언제든지 필요한 버전의 명령행 도구를 사용할 수 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;예제 : jq를 도커 컨테이너로 실행&#10;&lt;ul&gt;&#10;&lt;li&gt;Dockerfile&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-Dockerfile" data-lang="Dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;alpine:3.7&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; apk add --no-cache --virtual&lt;span class="o"&gt;=&lt;/span&gt;build-devs wget &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wget https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mv jq-linux64 /usr/local/bin/jq &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod +x /usr/local/bin/jq &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apk del build-devs&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/usr/local/bin/jq&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;-C&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CMD&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;이미지 빌드 및 태그 변경&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker image build -t ch10/jq:latest .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker image tag ch10/jq:latest ch10/jq:1.5&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;테스트&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ echo &amp;#39;{&amp;#34;version&amp;#34;:100}&amp;#39; | jq &amp;#39;.version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ echo &amp;#39;{&amp;#34;version&amp;#34;:100}&amp;#39; | docker container run -i --rm ch10/jq:1.5 &amp;#39;.version&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;alias로 &lt;code&gt;docker container run -i --rm ch10/jq:1.5&lt;/code&gt;를 &lt;code&gt;jq1.5&lt;/code&gt;로 등록하여 사용할 수 있다.&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ alias jq1.5=&amp;#39;docker container run -i --rm ch10/jq:1.5&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ echo &amp;#39;{&amp;#34;version&amp;#34;:100}&amp;#39; | jq1.5 &amp;#39;.version&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;도커 컨테이너로 셸 스크립트 실행하기&#10;&lt;ul&gt;&#10;&lt;li&gt;배포 및 운영과 관련된 내용을 포함하는 셸 스크립트를 다양한 도구를 이용해 실행하는 경우도 많다.&lt;/li&gt;&#10;&lt;li&gt;여러 도구를 한꺼번에 다루거나 처리 과정을 코드로 옮겨 작업할 수 있다면 작업 효율이 향상시킬 수 있을 것이다.&lt;/li&gt;&#10;&lt;li&gt;스크립트가 자신이 의존하는 도구나 라이브러리의 버전을 업데이트하면서 또 다른 도구의 동작이 달라지는 경우도 있다.&lt;/li&gt;&#10;&lt;li&gt;셸 스크립트가 가볍고 편리하기는 하나 모든 환경에서 같은 동작을 보장하려면 여러모로 신경 써야 한다.&lt;/li&gt;&#10;&lt;li&gt;환경 차이에서 오는 불필요한 트러블을 방지하려면 스크립트와 스크립트가 의존하는 도구를 함께 도커 컨테이너에 격리해 놓으면 된다.&lt;/li&gt;&#10;&lt;li&gt;예제 : 표준 출력으로 출력된 JSON 문서에서 지정한 속성의 속성값을 추출한다.&#10;&lt;ul&gt;&#10;&lt;li&gt;show-attr.sh 작성(따로 실행 권한(+x)을 주지 않아도 된다.)&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ATTR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$ATTR&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;required attribute name argument&amp;#34;&lt;/span&gt; 1&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;id&amp;#34;: 100,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;username&amp;#34;: &amp;#34;gihyo&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;comment&amp;#34;: &amp;#34;I like Alpine Linux&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt;}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq -r &lt;span class="s2"&gt;&amp;#34;.&lt;/span&gt;&lt;span class="nv"&gt;$ATTR&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;Dockerfile 작성&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-Dockerfile" data-lang="Dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;alpine:3.7&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; apk add --no-cache --virtual&lt;span class="o"&gt;=&lt;/span&gt;build-devs wget &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wget https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mv jq-linux64 /usr/local/bin/jq &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod +x /usr/local/bin/jq &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apk del build-devs&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; show-attr.sh /usr/local/bin/&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;sh&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/usr/local/bin/show-attr.sh&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CMD&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;빌드 및 실행&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker image build -t ch10/show-attr:latest .&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker container run --rm ch10/show-attr:latest username&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;마무리&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너 이전의 셸 스크립트는 스크립트가 의존하는 도구나 라이브러리의 관리 문제와 스크립트만 봐서는 환경 구축 시에 알아야 할 내용을 파악하기 어렵다.&lt;/li&gt;&#10;&lt;li&gt;컨테이너를 이용해 스크립트와 그 실행 환경 자체를 분리하면 이식성 확보는 문론이고 Dockerfile 안에 스크립트가 의존하는 도구 및 라이브러리가 한눈에 정리된다.&lt;/li&gt;&#10;&lt;li&gt;CI/CD 단계에서 스크립트를 포함하는 컨테이너 자체를 테스트할 수도 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="3-부하-테스트"&gt;3. 부하 테스트&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;테스트 환경 구축&lt;/p&gt;</description></item><item><title>부록 A : 보안</title><link>https://lameld.github.io/docker/ext-01-security/</link><pubDate>Tue, 14 Jul 2020 00:00:00 +0000</pubDate><guid>https://lameld.github.io/docker/ext-01-security/</guid><description>&lt;h2 id="1-공개된-도커-이미지의-안전성"&gt;1. 공개된 도커 이미지의 안전성&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;INTRO&#10;&lt;ul&gt;&#10;&lt;li&gt;공개적인 생태계의 특성상 악의적인 이미지가 포함될 가능성을 배제할 수 없다.&lt;/li&gt;&#10;&lt;li&gt;안전한 도커 이미지를 판단하는 기준을 파악하고 위험한 이미지를 가려내는 안목이 필요하다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;도커 허브&#10;&lt;ul&gt;&#10;&lt;li&gt;도커의 기본적인 레지스트리이다.&lt;/li&gt;&#10;&lt;li&gt;docker search 명령으로 도커 허브에 등록된 이미지를 검색할 수 있다.&#10;&lt;ul&gt;&#10;&lt;li&gt;정렬&#10;&lt;ul&gt;&#10;&lt;li&gt;리포지토리의 스타 수(인기)&lt;/li&gt;&#10;&lt;li&gt;pull 횟수&lt;/li&gt;&#10;&lt;li&gt;OFFICIAL 항목 : &lt;code&gt;[OK]&lt;/code&gt;라면 도커 허브의 공식 리포지토리&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;OFFICIAL&#10;&lt;ul&gt;&#10;&lt;li&gt;해당 소프트웨어의 전문가나 보안 전문가와 협조해 이미지의 품질을 담보하기 위한 리뷰를 거친 것&lt;/li&gt;&#10;&lt;li&gt;일정 수준의 보안성을 확보했다고 할 수 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;Quay.io&#10;&lt;ul&gt;&#10;&lt;li&gt;CoreOS에서 운영하는 Quay.io&lt;/li&gt;&#10;&lt;li&gt;사설 리포지토리 및 자동 빌드(automated build)를 지원한다.&lt;/li&gt;&#10;&lt;li&gt;조직 관련 기능으로 팀 구성 및 롤 설정 기능을 제공하므로 도커 허브보다 훨씬 충실하게 팀 개발을 뒷바침할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;Quay.io는 취약점 정보 데이터베이스이 CVE 정보를 기초로 설치된 패키지를 통해 취약점 포함 여부를 확인한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;Outro&#10;&lt;ul&gt;&#10;&lt;li&gt;도커 허브에서 제공하는 공식 이미지나 Quay.io의 취약점 검사 등은 이미지의 안전성을 평가할 수 있는 중요한 지표이다.&lt;/li&gt;&#10;&lt;li&gt;이 지표가 완벽한 것은 아니다.&lt;/li&gt;&#10;&lt;li&gt;계획 중인 유즈케이스에 따라 어떤 위험이 따르는지 직접 확인하는 것이 중요하다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="2-안전한-도커-이미지와-도커-운영-체제-꾸리기"&gt;2. 안전한 도커 이미지와 도커 운영 체제 꾸리기&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;INTRO&#10;&lt;ul&gt;&#10;&lt;li&gt;각 개발자가 안전한 도커 이미지를 만들고 보안 위험이 발생하지 않도록 운영 체계를 구축할 필요가 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;Docker Bench for Security&#10;&lt;ul&gt;&#10;&lt;li&gt;운영 환경에서 도커를 적용할 때 반드시 따라야 할 베스트 프랙티스의 준수 여부를 검사하는 도구&lt;/li&gt;&#10;&lt;li&gt;도커 컨테이너의 취약점을 발견하는 데 유용하다.&lt;/li&gt;&#10;&lt;li&gt;docker/docker-bench-security 이미지로 제공된다.&lt;/li&gt;&#10;&lt;li&gt;도커 호스트에서 실행&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;$&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;userns&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;cap&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="n"&gt;audit_control&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="n"&gt;DOCKER_CONTENT_TRUST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;systemd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;systemd&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;bench_security&lt;/span&gt; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;bench&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;security&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;실행 중인 컨테이너뿐만 아니라 도커 환경 전반에 걸친 취약점을 검사한다.&lt;/li&gt;&#10;&lt;li&gt;Docker daemon configuration : 도커 데몬의 설정을 검사&#10;&lt;ul&gt;&#10;&lt;li&gt;TLS/SSL이 적용되지 않은 비보안 레지스트리를 사용하고 있다면 &lt;code&gt;2.4 - Ensure insecure registries are not used&lt;/code&gt; 경고를 띄운다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;Container Images and Build File : Dockerfile에 대한 검사&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너 안에 어플리케이션 실행만을 위한 별도의 유저가 없다면 &lt;code&gt;4.1 - Ensure a user for the container has been created&lt;/code&gt; 경고를 띄운다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;운영 중 노출되기 쉬운 취약점을 탐지할 수 있으며 이 취약점을 해결하기 위한 베스트 프랙티스를 제시해 준다.&lt;/li&gt;&#10;&lt;li&gt;탐지된 취약점을 충분히 이해하는 것이 중요하다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;컨테이너에 파일을 추가하면서 발생하는 위험&#10;&lt;ul&gt;&#10;&lt;li&gt;Dockerfile로 컨테이너에 파일을 추가하는 인스트럭션 : ADD, COPY&#10;&lt;ul&gt;&#10;&lt;li&gt;COPY&#10;&lt;ul&gt;&#10;&lt;li&gt;호스트에서 파일이나 디렉터리를 복사해오는 기능을 수행&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;ADD&#10;&lt;ul&gt;&#10;&lt;li&gt;지정한 URL에서 파일을 내려받아 추가할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;압축 파일을 자동으로 해제하는 기능이 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;두 인스트럭션은 적절히 용도를 나눠 사용하지 않으면 취약점이 생길 수 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;URL에서 내려받은 파일이 항상 안전하다는 보장이 없다.&#10;&lt;ul&gt;&#10;&lt;li&gt;파일이 웹 사이트 소유자에 의해 변경될 수 있다.&lt;/li&gt;&#10;&lt;li&gt;악의를 품은 제삼자가 파일을 변조했을 수 있다.&lt;/li&gt;&#10;&lt;li&gt;이미지가 빌드될 때마다 결과물도 달라질 것이므로 항등성도 담보할 수 없다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;ADD 인스트럭션을 사용하려면 추가하려는 파일의 안전성을 먼저 검증해야 한다.&lt;/li&gt;&#10;&lt;li&gt;Dockerfile에는 ADD 인스트럭션 대신 COPY 인스트럭션을 사용하는 버릇을 들이는 것이 좋다.&lt;/li&gt;&#10;&lt;li&gt;RUN&#10;&lt;ul&gt;&#10;&lt;li&gt;wget이나 curl을 이용해 추가하는 방법도 있다.&lt;/li&gt;&#10;&lt;li&gt;호스트로부터 파일을 추가하는 게 아니라 파일 추가 과정 자체를 컨테이너 안으로 국한 시킬 수 있기 때문에 이식성이 뛰어나다.&lt;/li&gt;&#10;&lt;li&gt;ADD 인스트럭션과 마찬가지의 취약점을 가질 수 있다는 점을 이해하고 사용해야 한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;예제 : 프로비저닝 도구 Terraform&#10;&lt;ul&gt;&#10;&lt;li&gt;Terraform은 실행 파일을 포함하는 zip 파일과 함께 SHA256으로 생성한 체크섬 정보를 제공한다.&lt;/li&gt;&#10;&lt;li&gt;적합성 검사 Dockerfile&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-Dockerfile" data-lang="Dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;alpine:3.7&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ENV&lt;/span&gt; &lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.11.5&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; apk --no-cache add --virtual&lt;span class="o"&gt;=&lt;/span&gt;build-devs curl gnupg&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# terraform과 배포 파일 체크섬 정보를 받음&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt; https://releases.hashicorp.com/terraform/&lt;span class="nv"&gt;$VERSION&lt;/span&gt;/terraform_&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;_linux__amd64.zip .&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt; https://releases.hashicorp.com/terraform/&lt;span class="nv"&gt;$VERSION&lt;/span&gt;/terraform_&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;_SHA256SUMS .&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt; https://releases.hashicorp.com/terraform/&lt;span class="nv"&gt;$VERSION&lt;/span&gt;/terraform_&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;_SHA256.sig .&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Keybase에 공개된 Hashicorp사의 PGP 공개키 임포트&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; curl https://keybase.io/hashicorp/pgp_keys.asc &lt;span class="p"&gt;|&lt;/span&gt; gpg --import&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# 체크섬의 전자서명 검증&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; gpg --verify terraform_&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;_SHA256SUMS.sig terraform_&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;_SHA256SUMS&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# 압축 파일의 체크섬 검증&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; cat terraform_&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;_SHA256SUMS &lt;span class="p"&gt;|&lt;/span&gt; grep linux_amd64 &lt;span class="p"&gt;|&lt;/span&gt; sha256sum -cs&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; unzip terraform_&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;_linux_amd64.zip&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; mv terraform /usr/local/bin/&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; terraform -v&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;Terraform을 개발한 Hashicorp는 Keybase에 PGP 공개키를 공개 중이다.&lt;/li&gt;&#10;&lt;li&gt;체크섬 정보의 서명을 검증한다.&lt;/li&gt;&#10;&lt;li&gt;서명이 확인되면 이 체크섬 정보를 zip 파일로부터 계산한 체크섬과 비교하는 방법으로 zip 파일의 정합성을 검증할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;체크섬 정보가 일치하지 않는다면 빌드는 실패 처리된다.&lt;/li&gt;&#10;&lt;li&gt;외부로 공개되는 Dockerfile에 이런 방식으로 검증 로직을 추가하면 이미지의 신뢰성을 향상시킬 수 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;적절한 접근 제어&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너를 침입으로부터 보호&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너 중심의 개발 및 운영에서 가장 중요한 것은 외부인의 컨테이너 침입을 방지하는 것이다.&lt;/li&gt;&#10;&lt;li&gt;대책&#10;&lt;ul&gt;&#10;&lt;li&gt;root로 로그인 금지.&lt;/li&gt;&#10;&lt;li&gt;AWS의 보안 그룹, GCP의 방화벽을 적절히 설정하고 도커 호스트에 대한 접근 제어.&lt;/li&gt;&#10;&lt;li&gt;VPN 적용 및 내부망 접근 제한.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;/var/run/docker.sock의 컨테이너와의 공유 금지&#10;&lt;ul&gt;&#10;&lt;li&gt;도커는 유닉스 도메인 소켓 /var/run/docker.sock을 -v 옵션으로 마운트하고 이를 이용해 원격지의 도커 데몬에 접근한다.&lt;/li&gt;&#10;&lt;li&gt;이 소켓에 접근을 허용하면 컨테이너 생성 등의 작업을 원하는 대로 지시할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;/var/run/docker.sock을 사용하는 이미지의 사용은 원칙적으로 금해야 한다.&lt;/li&gt;&#10;&lt;li&gt;배포 중인 Dockerfile을 살펴보고 보호 대책을 마련해야 한다.&lt;/li&gt;&#10;&lt;li&gt;특별한 사정이 없다면 호스트의 /var/run/docker.sock을 컨테이너 마운트하는 일은 하지 않는 것이 좋다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;컨테이너 어플리케이션 실행용 사용자 추가&#10;&lt;ul&gt;&#10;&lt;li&gt;도커 컨테이너 안에서 어플리케이션을 실행하는 기본 사용자 : root&lt;/li&gt;&#10;&lt;li&gt;도커 이미지를 빌드하는 과정이라면 root 권한을 갖는 쪽이 편하다. 하지만 이것이 보안에 큰 구멍이 될 수 있다.&lt;/li&gt;&#10;&lt;li&gt;도커는 호스트의 리소스를 컨테이너에서 공유하는 기술적 특징을 갖는다. 사용자 UID도 예외가 아니다.&lt;/li&gt;&#10;&lt;li&gt;모종의 경로를 통해 컨테이너에 침입했다면 사실상 호스트의 root 권한을 탈취한 것과 같다.&lt;/li&gt;&#10;&lt;li&gt;이런 문제를 방지하기 위해서 useradd 명령으로 어플리케이션 실행용 사용자를 생성하고 USER 인스트럭션에서 해당 사용자를 지정하면 된다.&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-Dockerfile" data-lang="Dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;golang:1.9&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; mkdir /echo&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; main.go /echo/&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; useradd gihyo&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;gihyo&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CMD&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;go&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;run&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/echo/main.go&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#10;&lt;li&gt;컨테이너를 실행해 보면 gihyo 상용자가 어플리케이션을 실행하고 있음을 알 수 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;기밀정보 취급&#10;&lt;ul&gt;&#10;&lt;li&gt;환경 변수를 이용하는 방법&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너의 환경 변수 값은 너무 간단히 노출된다.&#10;&lt;ul&gt;&#10;&lt;li&gt;env 명령만 사용할 수 있다면 모든 환경 변수 값을 볼 수 있다.&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;docker container inspect &amp;lt;컨테이너 ID&amp;gt;&lt;/code&gt;명령도 같다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;환경 변수 방식을 적용하려면 권한 없는 제삼자가 도커 호스트나 도커 데몬을 조작할 수 없도록 적절한 접근 통제 정책을 먼저 실시해야 한다.&lt;/li&gt;&#10;&lt;li&gt;제삼자에게 기밀정보가 유출되어도 상관없도록 기밀정보 자체를 암호화하고 어플리케이션 안에서만 복호화할 수 있도록 구현하는 것도 좋은 방법이다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;기밀정보를 외부에서 받아오는 방법&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너 안에 있는 어플리케이션이 직접 외부에서 기밀정보를 받아오는 방법이 있다.&lt;/li&gt;&#10;&lt;li&gt;컨테이너에 접근하더라도 사용자는 아무런 기밀정보를 볼 수 없으며 어플리케이션이 원격지에 위치한 기밀정보를 참조해오는 방식이다.&lt;/li&gt;&#10;&lt;li&gt;이 기밀정보는 기계만 읽을 수 있는 형태이므로 기밀정보를 받아오는 통신 내용이 암호화되고 적절한 접근 통제만 되면 극히 안전한 방법이다.&lt;/li&gt;&#10;&lt;li&gt;예시&#10;&lt;ul&gt;&#10;&lt;li&gt;아마존 S3에 저장된 기밀정보에 접근하기 위해 IAM을 이용하는 방법이 있다.&lt;/li&gt;&#10;&lt;li&gt;Hashicorp가 개발한 Vault가 있다.&#10;&lt;ul&gt;&#10;&lt;li&gt;기밀정보를 저장하는 도구.&lt;/li&gt;&#10;&lt;li&gt;어플리케이션을 기밀정보를 전달받는 데이터베이스로 활용할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;암호화 기능, 기밀정보 열람 로그 기능, 무효화 기능 등을 제공한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;</description></item><item><title>부록 B : 도커로 개발을 지원하는 도구 및 서비스</title><link>https://lameld.github.io/docker/ext-02-tools/</link><pubDate>Fri, 10 Jul 2020 00:00:00 +0000</pubDate><guid>https://lameld.github.io/docker/ext-02-tools/</guid><description>&lt;h2 id="1-인하우스-도커-레지스트리-구축"&gt;1. 인하우스 도커 레지스트리 구축&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;도커 이미지를 보관하기에는 도커 허브나 Quay.io 같은 퍼블릭 레지스트리 서비스를 이용하는 것이 편리하다.&lt;/li&gt;&#10;&lt;li&gt;퍼블릭 레지스트리를 사용 불가한 경우&#10;&lt;ul&gt;&#10;&lt;li&gt;퍼블릭 레지스트리의 지나치게 긴 응답 시간&lt;/li&gt;&#10;&lt;li&gt;보안 측면의 문제&#10;&lt;ul&gt;&#10;&lt;li&gt;운영 환경에 배포하기 위해 개발한 어플리케이션 이미지를 퍼블릭 레지스트리에 저장할 수는 없다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;인하우스 도커 레지스트리&#10;&lt;ul&gt;&#10;&lt;li&gt;레지스트리를 직접 구축하여 어떤 보안 정책이라도 만족시킬 수 있다.&lt;/li&gt;&#10;&lt;li&gt;컨테이너를 배포하는 호스트와 가까이 도커 레지스트리가 위치할 것이므로 배포 속도 또한 개선할 수 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;Registry(Docker Distribution)&#10;&lt;ul&gt;&#10;&lt;li&gt;도커에서 인하우스 도커 레지스트리를 구축할 수 있도록 배포하는 도구&lt;/li&gt;&#10;&lt;li&gt;Docker Distribution과 함께 제공된다.&lt;/li&gt;&#10;&lt;li&gt;오픈소스 소프트웨어이며 도커 컨테이너 형태로 실행할 수 있으므로 도커 호스트 역할을 할 운영 체제만 있으면 레지스트리 운영이 가능하다.&lt;/li&gt;&#10;&lt;li&gt;3장의 docker swarm을 구축할 때 사용했다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;구축&#10;&lt;ul&gt;&#10;&lt;li&gt;Registry 설치(서버) : ubuntu 16.x&#10;&lt;ul&gt;&#10;&lt;li&gt;/etc/systemd/system/docker-container@registry.service&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[Unit]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Descriptioni=Registry&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Requires=docker.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;After=docker.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[Service]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Restart=always&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ExecStart=/usr/bin/docker container run --rm --name registry -p 5000:5000 library/registry&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[Install]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WantedBy=multi-user.target&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;서비스로 활성화 한다.&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ systemctl enable docker-container@registry.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ systemctl start docker-container@registry.service&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;곧 registry 컨테이너가 실행된다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;Registry에 이미지 등록하기&#10;&lt;ul&gt;&#10;&lt;li&gt;Registry는 HTTP API를 제공한다.&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ curl http://localhost:5000/v2/_catalog&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;태그를 부여해 기존 알파인 리눅스 이미지를 Registry에 등록한다.&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker image pull alpine:3.7&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker image tag alpine:3.7 localhost:5000/alpine:3.7&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker image push localhost:5000/alpine:3.7&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;Registry에서 이미지 내려받기&#10;&lt;ul&gt;&#10;&lt;li&gt;Registry 컨테이너를 실행한 호스트에서 localhost:5000으로 접근하면 된다.&lt;/li&gt;&#10;&lt;li&gt;그 외 호스트에서 Registry에서 접근하려면 도메인 부분을 다른 호스트에서 참조 가능한 IP 주소나 호스트명으로 바꿔야 한다.&lt;/li&gt;&#10;&lt;li&gt;docker image pull 명령은 기본적으로 HTTPS를 통해 레지스트리에 접근하기 때문에 Registry 역시 HTTPS를 활성화 하지 않으면 오류가 발생한다.&lt;/li&gt;&#10;&lt;li&gt;외부에서 접근이 불가능한 내부 네트워크 안에서만 이미지가 전송된다면 굳이 HTTPS를 적용할 필요가 없다.&#10;&lt;ul&gt;&#10;&lt;li&gt;docker image pull 명령을 실행하는 쪽의 /etc/docker/daemon.json 파일에 HTTP 통신을 허용한다.&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;Insecure registries&lt;/code&gt;에 값을 추가한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="2-도커와-cicd-서비스-연동"&gt;2. 도커와 CI/CD 서비스 연동&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;도커를 사용한 어플리케이션 개발 과정&#10;&lt;ul&gt;&#10;&lt;li&gt;구현 - 단위 테스트 - 어플리케이션 빌드 - 도커 이미지 빌드 - 도커 레지스트리 등록&lt;/li&gt;&#10;&lt;li&gt;위 과정의 반복&lt;/li&gt;&#10;&lt;li&gt;이 과정을 수작업으로 진행하면 실수가 발생하기 쉽다.&lt;/li&gt;&#10;&lt;li&gt;CI/CD 서비스에 이 과정을 맡기면 실수를 줄이고 시간도 적야할 수 있으므로 적절한 자동화 도입이 매우 중요하다.&#10;&lt;ul&gt;&#10;&lt;li&gt;CI : Continuous Integrate : 지속적 통합&lt;/li&gt;&#10;&lt;li&gt;CD : Continuous (Deploy | Delivery) : 지속적 배포&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;CI/CD 서비스의 예시 : Jenkins, CircleCI&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;CircleCI&#10;&lt;ul&gt;&#10;&lt;li&gt;INTRO&#10;&lt;ul&gt;&#10;&lt;li&gt;SaaS(Software As A Service) 형태로 제공되는 CI/CD 서비스&lt;/li&gt;&#10;&lt;li&gt;빌드 설정 역시 yaml 포맷으로 기술할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;이번에 다루는 내용은 CircleCI와 github를 사용한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;github 계정으로 OAuth 인증을 거쳐 가입하고 로그인한다.&lt;/li&gt;&#10;&lt;li&gt;프로젝트 추가&#10;&lt;ul&gt;&#10;&lt;li&gt;github에 리포지토리를 새로 추가하고 내용으로 Dockerfile과 main.py를 생성한다.&#10;&lt;ul&gt;&#10;&lt;li&gt;Dockerfile&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-Dockerfile" data-lang="Dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;python:3.6-alpine&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/app&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; main.py /app/main.py&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CMD&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;python&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;main.py&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;main.py&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# -*- coding: utf-8 -*-&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;socket&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# simple-echo-server&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;0.0.0.0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;connected by&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sendall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;hello python!!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;프로젝트가 추가되면 대상 저장소에 푸시가 일어날 때마다 웹훅이 CircleCI의 CI/CD 잡을 시작하게 한다.&lt;/li&gt;&#10;&lt;li&gt;깃허브 조직 저장소를 추가하려면 깃 허브 설정에서 CircleCI의 Organization access 권한을 부여해야 한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;빌드 설정 파일 작성&#10;&lt;ul&gt;&#10;&lt;li&gt;python 저장소를 이용해 도커 이미지 빌드에 이르는 과정을 설정한다.&lt;/li&gt;&#10;&lt;li&gt;.circleci/config.yml&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yml" data-lang="yml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2.1&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# CircleCI 컨테이너의 작업 디렉토리&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;working_directory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/app&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 잡을 실행하는 컨테이너의 도커 이미지&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;docker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;python:3.6-alpine&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;checkout &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 저장소에서 소스코드를 체크아웃&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;persist_to_workspace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# workspace를 후속 잡에서 사용할 수 있도록 유지&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;.&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;.&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;docker_build_push&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;working_directory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/app&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;docker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;docker:18.05.0-ce-dind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# docker 명령을 사용할 수 있는 컨테이너&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;attach_workspace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 저장해둔 workspace를 배치&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;.&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;setup_remote_docker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# docker image build를 수행할 데몬 준비&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18.05.0&lt;/span&gt;-&lt;span class="l"&gt;ce&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 도커 이미지 빌드&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;docker image build&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;docker image build -t joonstudydocker/echo-python:latest .&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 빌드된 이미지 확인&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;docker image ls&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;docker image ls&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 도커 허브 로그인&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;docker login&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;docker login -u $DOCKER_USER -p $DOCKER_PASS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 프로젝트 설정에서 환경 변수를 저장할 수 있다.&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# latest 이미지를 도커 허브에 등록&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;release latest&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;docker image push joonstudydocker/echo-python:latest&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;workflows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;build_and_push&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# workflows로 실행할 잡을 열거&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;build&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;docker_build_push&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;requires&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# build 잡 다음에 실행&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;build&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# master 브랜치인 경우에만 실행&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 다른 브랜치에서도 실행하려면 주석 처리하거나 제거&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;only&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;master&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;CircleCI와 저장소를 연동하여 어플리케이션 테스트 및 도커 이미지 빌드와 등록을 대신해주는 CI/CD 환경을 구축하였다.&lt;/li&gt;&#10;&lt;li&gt;참고&#10;&lt;ul&gt;&#10;&lt;li&gt;docker login 오류 - ubuntu16.x&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ sudo apt install gnupg2 pass &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ gpg2 --full-generate-key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ gpg2 -k&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pass init &amp;#34;whatever key id you have&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="3-ecs에서-aws-fargate를-이용한-컨테이너-오케스트레이션"&gt;3. ECS에서 AWS Fargate를 이용한 컨테이너 오케스트레이션&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;ECS - Elastic Container Service&#10;&lt;ul&gt;&#10;&lt;li&gt;AWS는 지금까지 독자적인 컨테이너 오케스트레이션 서비스 ECS를 제공해왔다.&lt;/li&gt;&#10;&lt;li&gt;ESC는 서버 여러대를 이용해 컨테이너 오케스트레이션을 구현하는 방식이다.&lt;/li&gt;&#10;&lt;li&gt;ALB라는 AWS 서비스와 매끄럽게 연동된다.&#10;&lt;ul&gt;&#10;&lt;li&gt;ALB - Application Load Balancer&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;ECS는 최초 도입이 쿠버네티스보다 쉽기 때문에 프로젝트 규모와 무관하게 널리 사용된다.&#10;&lt;ul&gt;&#10;&lt;li&gt;넷플릭스에서 대규모로 운영한 실적이 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;AWS Fargate&#10;&lt;ul&gt;&#10;&lt;li&gt;개발자가 서버나 클러스터를 직접 관리하지 않고 컨테이너를 실행하는 기술&lt;/li&gt;&#10;&lt;li&gt;ECS나 EKS에서는 서버관리, 클러스터 프로비저닝 등을 담당하는 서비스이다.&lt;/li&gt;&#10;&lt;li&gt;컨테이너 오케스트레이션부터 서버 및 클러스터 관리에 이르기까지 가장 손이 많이 가는 작업을 제거했다는 점에서 획기적이라 할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;AWS Fargate는 AWS Lambda의 뒤를 잇는 차세대 서버리스 기술로서도 주목받고 있다.&#10;&lt;ul&gt;&#10;&lt;li&gt;Lambda는 장시간 실행되는 배치 어플리케이션에는 적합하지 않은데, ECS는 이러한 약점을 보완할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;AWS Fargate는 서버 인스턴스를 신경 쓰지 않고도 간단히 컨테이너 오케스트레이션을 실현할 수 있으므로 컨테이너 기술 및 서버리스 기술 양쪽에서 새로운 트랜드가 될 것이다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;Fargate로 ECS 클러스터 구축&#10;&lt;ul&gt;&#10;&lt;li&gt;AWS console에서 ECS를 선택하면 Fargate 마법사 화면이 나타난다.&lt;/li&gt;&#10;&lt;li&gt;시작을 눌러서 설정을 시작한다.&lt;/li&gt;&#10;&lt;li&gt;1단계 : 컨테이너 및 작업&#10;&lt;ul&gt;&#10;&lt;li&gt;nginx를 선택한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;2단계 : 서비스&#10;&lt;ul&gt;&#10;&lt;li&gt;로드 밸런서 유형을 Application Load Balancer를 선택한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;3단계 : 클러스터&#10;&lt;ul&gt;&#10;&lt;li&gt;Cluster 이름을 설정한다.&lt;/li&gt;&#10;&lt;li&gt;필자는 joon으로 하겠다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;4단계 : 검토&#10;&lt;ul&gt;&#10;&lt;li&gt;지금까지의 내용을 검토한 뒤에 생성을 누른다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;생성 뒤 확인&#10;&lt;ul&gt;&#10;&lt;li&gt;ECS 관련 리소스가 수 분 만에 생성된다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;생성된 nginx에 접속&#10;&lt;ul&gt;&#10;&lt;li&gt;생성한 뒤 로드 밸러서를 확인한다.&lt;/li&gt;&#10;&lt;li&gt;ECS 클러스터에 배포된 컨테이너는 모두 ALB라는 로드 밸런서를 통해 접근하므로 지금 만든 ALB의 DNS name을 복사한다.&lt;/li&gt;&#10;&lt;li&gt;웹 브라우저에서 &amp;lsquo;http://복사한도메인&amp;rsquo;에 접근하면 nginx의 welcome 화면을 볼 수 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;ECS를 조작해 어플리케이션 배포하기&#10;&lt;ul&gt;&#10;&lt;li&gt;ECS 리소스&#10;&lt;ul&gt;&#10;&lt;li&gt;(작음) Container Definition - Task Definition - Service - Cluster (큼)&lt;/li&gt;&#10;&lt;li&gt;Container Definition : 배포되는 각 컨테이너의 정의&lt;/li&gt;&#10;&lt;li&gt;Task Definition : 컨테이너의 집합인 Task의 정의&lt;/li&gt;&#10;&lt;li&gt;쿠버네티스 파드의 개념이 두 단계로 나뉘어 있다고 생각하면 된다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;Task Definition 생성&#10;&lt;ul&gt;&#10;&lt;li&gt;작업 정의 - 새로운 작업 정의 작성&lt;/li&gt;&#10;&lt;li&gt;FARGATE를 선택하고 다음을 누른다.&lt;/li&gt;&#10;&lt;li&gt;테스크 정의 이름은 echo-task로 한다.&lt;/li&gt;&#10;&lt;li&gt;네트워크 모드는 awsvpc를 선택하여 내부 IP(private)만 부여한다.&lt;/li&gt;&#10;&lt;li&gt;CPU 리소스&#10;&lt;ul&gt;&#10;&lt;li&gt;memory : 0.5GB&lt;/li&gt;&#10;&lt;li&gt;CPU : 0.25vCPU&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;컨테이너 정의&#10;&lt;ul&gt;&#10;&lt;li&gt;echo&#10;&lt;ul&gt;&#10;&lt;li&gt;이름 : echo&lt;/li&gt;&#10;&lt;li&gt;이미지 : stormcat24/echo:latest&lt;/li&gt;&#10;&lt;li&gt;포트 맵핑 : 8080&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;nginx&#10;&lt;ul&gt;&#10;&lt;li&gt;이름 : nginx&lt;/li&gt;&#10;&lt;li&gt;이미지 : stormcat24/nginx-proxy:latest&lt;/li&gt;&#10;&lt;li&gt;포트 맵핑 : 80&lt;/li&gt;&#10;&lt;li&gt;환경변수&#10;&lt;ul&gt;&#10;&lt;li&gt;BACKEND_HOST : value : localhost:8080&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;서비스 수정&#10;&lt;ul&gt;&#10;&lt;li&gt;새 배포 적용을 체크한다.&lt;/li&gt;&#10;&lt;li&gt;작업 개수는 1로 한다.&lt;/li&gt;&#10;&lt;li&gt;이후 화면은 수정 없이 다음을 클릭한다.&lt;/li&gt;&#10;&lt;li&gt;Service 수정이 끝나면 이미 배포된 태스크가 정지되며 echo-task:1 태스크가 하나 배포된다.&lt;/li&gt;&#10;&lt;li&gt;태스크 상세 정보를 확인하면 echo와 nginx 컨테이너를 포함한 태스크가 배포된 것을 알 수 있다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;ALB와 대상 그룹&#10;&lt;ul&gt;&#10;&lt;li&gt;Service는 ABL와 연동해 외부로부터 접근할 수 있다.&lt;/li&gt;&#10;&lt;li&gt;RUNNING 상태가 된 태스크는 ALB가 확인한 헬스 체크 결과가 healthy로 나와야 비로소 트래픽이 전달된다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;OUTRO&#10;&lt;ul&gt;&#10;&lt;li&gt;도커로 운영 환경을 꾸린다 해도 서버나 클러스터를 계속 신경써야 할 것이다.&lt;/li&gt;&#10;&lt;li&gt;그러나 Fargate를 사용하면 한 번 설정하면 그 이후에는 자동으로 제어된다.&lt;/li&gt;&#10;&lt;li&gt;이는 도커를 적용한 운영 환경을 쾌적하게 해주는 기술이다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;</description></item><item><title>부록 C : 주요 명령어 정리</title><link>https://lameld.github.io/docker/ext-03-command/</link><pubDate>Fri, 10 Jul 2020 00:00:00 +0000</pubDate><guid>https://lameld.github.io/docker/ext-03-command/</guid><description>&lt;h2 id="1-도커-명령어"&gt;1. 도커 명령어&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker image build [options] (Dockerfile경로 | URL)&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Dockerfile로부터 도커 이미지를 빌드&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker search [options] 키워드&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;도커 허브에서 제공되는 도커 이미지를 검색&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker image pull [options] 리포지토리명[:태그명]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;도커 레지스트리에서 도커 이미지를 다운로드&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker image ls [options] [리포지토리명[:태그명]]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;해당 도커 호스트가 보유한 도커 이미지의 목록을 출력&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker image tag 이미지원래이름[:태그] 이미지새이름[:태그]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;도커 이미지 태그를 생성&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker image push [options] 리포지토리명[:태그명]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;도커 레지스트리에 도커 이미지를 전송해 등록&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker container run [options] 이미지명[:태그명] [명령] [명령인자 ...]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;도커 컨테이너를 새로 실행&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker container ls [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;dockerd가 보유한 컨테이너 목록 출력&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker container stop [options] (컨테이너ID | 컨테이너명)&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;실행중인 컨테이너를 정지&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker container restart [options] (컨테이너ID | 컨테이너명)&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;정지한 컨테이너를 다시 실행&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker container rm [options] (컨테이너ID | 컨테이너명)&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너를 디스크에서 삭제&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker container logs [options] (컨테이너ID | 컨테이너명)&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너의 로그(표준 출력)를 화면에 출력&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker container exec -it [options] (컨테이너ID | 컨테이너명) 컨테이너에서_실행할_명령&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;실행 중인 컨테이너에서 명령어를 실행&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker container cp [options] (컨테이너ID | 컨테이너명):원본파일 대상파일&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너에서 호스트로 파일 및 디렉토리 복사&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker container cp [options] 호스트_원본파일 (컨테이너ID | 컨테이너명):대상파일&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;호스트에서 컨테이너로 파일 및 디렉토리 복사&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker container prune [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;정지 상태인 모든 컨테이너를 디스크에서 삭제&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker image prune [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;사용하지 않는 모든 도커 이미지를 디스크에서 삭제&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker system prune [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;사용하지 않는 컨테이너 및 이미지, 볼륨, 네트워크 등 모든 도커 리소스를 일괄 삭제&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker container stats [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;시스템 리소스 사용 현황을 컨테이너 단위로 실시간 출력&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="2-dockerfile-인스트럭션"&gt;2. Dockerfile 인스트럭션&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;FROM&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;빌드하는 이미지의 기반 이미지를 지정&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;RUN&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;이미지를 빌드할 때 컨테이너에서 실행할 명령어를 정의&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;COPY&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;호스트에서 컨테이너로 파일 및 디렉토리를 복사&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;ADD&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;COPY의 기능에 압축 파일 자동 해제 및 URL로부터 컨테이너에 파일 및 디렉토리 추가&lt;/li&gt;&#10;&lt;li&gt;운영 체제를 담은 기반 이미지를 만들 때처럼 특수한 경우에 활용&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;CMD&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너에서 포어그라운드로 실행할 명령어 정의&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;ENTRYPOINT&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너를 실행 가능 파일로 사용할 때 정의하는 명령&lt;/li&gt;&#10;&lt;li&gt;CMD와 ENTRYPOINT를 함께 사용할 수 있음&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;ARG&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;docker image build&lt;/code&gt;를 실행할 때 사용하는 변수&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;ENV&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너 안의 환경 변수를 정의&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;EXPOSE&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너가 노출하는 포트&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;VOLUME&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;호스트나 다른 컨테이너에서 마운트할 수 있는 포인트 생성&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;LABEL&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;이미지에 추가하는 메타 데이터&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;STOPSIGNAL&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너에 전달되면 컨테이너를 종료하는 시스템 시그널 설정&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;HEALTHCHECK&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너 안에서 명령을 실행하고 그 결과를 헬스 체크에 사용&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;USER&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너 실행 시 컨테이너 사용자. 이미지 빌드 시 USER 정의 뒤에 나오는 RUN 인스트럭셔도 해당 사용자 권한으로 실행&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;WORKDIR&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너의 작업 디렉토리&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;ONBUILD&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컨테이너 안에서 실행되는 명령을 정의&lt;/li&gt;&#10;&lt;li&gt;이미지에서는 실행되지 않음&lt;/li&gt;&#10;&lt;li&gt;ONBUILD를 정의한 이미지를 기반 이미지로 삼아 다른 이미지를 빌드할 때 실행&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="3-도커-컴포즈-명령어"&gt;3. 도커 컴포즈 명령어&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker-compose build [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컴포즈로 관리하는 서비스를 이미지로부터 빌드&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker-compose create [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컴포즈로 관리하는 서비스를 생성&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker-compose start [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컴포즈로 관리하는 서비스를 시작&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker-compose up [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컴포즈로 관리하는 서비스를 생성 및 시작&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker-compose stop [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컴포즈로 실행 중인 서비스를 정지&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker-compose rm [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컴포즈로 실행 중인 서비스를 삭제&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker-compose down [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컴포즈로 실행 중인 서비스를 정지 및 삭제&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker-compose ps [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컴포즈로 실행 중인 컨테이너의 목록을 출력&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker-compose logs [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;컴포즈로 실행 중인 컨테이너의 로그를 요약해 출력&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="4-도커-스웜스택-명령어"&gt;4. 도커 스웜/스택 명령어&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker swarm init [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;스웜 클러스터를 초기화&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker swarm join [options] manager 호스트:포트&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;스웜 클러스터에 노드 혹은 매니저를 추가&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker swarm leave [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;스웜 클러스터에서 노드 혹은 매니저를 제거&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker stack deploy [options] 스택명&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;스웜 클러스터에 스택을 배포&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker stack (ls | list) [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;스웜 클러스터에 배포된 스택 목록을 출력&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker stack ps [options] 스택명&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;스택 안에서 실행 중인 태스크를 출력&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker stack (rm | remove | down) [options] 스택명&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;스웜 클러스터에서 스택을 제거&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ docker stack services [options] 스택명&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;스택에 포함된 서비스 목록을 출력&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="5-헬름-명령어"&gt;5. 헬름 명령어&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm init [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;헬름을 초기화해 대상 쿠버네티스 클러스터를 배포할 수 있는 상태로 만든다.&lt;/li&gt;&#10;&lt;li&gt;옵션&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;--service-account&lt;/code&gt; : 틸러가 사용할 서비스 계정&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;--node-selector&lt;/code&gt; : 틸러를 배포할 노드의 레이블&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;--upgrade&lt;/code&gt; : 틸러 업그레이드&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;--history-max&lt;/code&gt; : 리소스 하나당 유지할 히스토리 최대 수&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm version&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;헬름 명령행 도구와 틸러의 버전을 확인한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm create 차트명&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;헬름 차트의 템플릿을 생성한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm lint 차트명&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;생성된 차트 템플릿이나 Chart.yaml, values.yaml 파일이 문법에 어긋나지 않는지 검사한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm package [options] 차트_경로&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;차트를 압축 파일로 패키징한다.&lt;/li&gt;&#10;&lt;li&gt;옵션&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;--version&lt;/code&gt; : 차트의 버전&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;-d, --destination&lt;/code&gt; : 압축 파일을 출력할 디렉토리&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm repo list&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;헬름 명령행 도구로 사용할 수 있는 차트 리포지토리 목록을 출력한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm repo add 리포지토리명 리포지토리URL&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;차트 리포지토리를 추가한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm repo remove 리포지토리명&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;현재 등록된 차트 리포지토리를 삭제한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm repo update&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;등록된 차트 리포지토리에서 최신 차트 정보를 받아온다.&lt;/li&gt;&#10;&lt;li&gt;반아온 정보는 로컬에 캐시되어 &lt;code&gt;helm search&lt;/code&gt; 명령 등에 사용된다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm search [검색키워드] [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;등록된 차트 리포지토리에서 원하는 차트 정보를 검색한다.&lt;/li&gt;&#10;&lt;li&gt;옵션&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;-r, --regexp&lt;/code&gt; : 키워드에 정규 표현식을 사용&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;-l, --version&lt;/code&gt; : 리포지토리에 등록된 버전 목록을 출력&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm fetch [options] 차트URL | 차트 리포지토리나 차트명&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;차트 리포지토리에서 패키지를 내려받는다.&lt;/li&gt;&#10;&lt;li&gt;옵션&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;--version&lt;/code&gt; : 내려받을 차트의 버전&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;사용 예시&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm fetch stable/redis&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm fetch stable/redis --version 3.6.0&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm serve [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;로컬 리포지토리로 사용할 웹 서버를 시작한다.&lt;/li&gt;&#10;&lt;li&gt;옵션&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;--address&lt;/code&gt; : 서버가 개방할 주소(기본값은 127.0.0.1)&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;--repo-path&lt;/code&gt; : 차트 리포지토리가 될 로컬 디렉터리 경로&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm install 차트리포지토리/차트명 [optinos]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;차트를 이용해 어플리케이션을 설치한다.&lt;/li&gt;&#10;&lt;li&gt;옵션&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;--dry-run&lt;/code&gt; : 설치 시뮬레이션을 수행한다.&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;--name&lt;/code&gt; : 릴리즈명(미지정 시 자동 생성)&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;-f, --value&lt;/code&gt; : YAML 파일의 경로 또는 URL(여러 개 지정 가능)&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;--version&lt;/code&gt; : 차트의 버전 지정&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm upgrade 릴리즈명 차트리포지토리명/차트명 [options]&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;기존에 설치된 릴리즈를 업데이트한다.&lt;/li&gt;&#10;&lt;li&gt;옵션&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;-f, --values&lt;/code&gt; : YAML 파일의 경로 혹은 URL(여러 개 지정 가능)&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;--version&lt;/code&gt; : 차트의 버전&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;--install&lt;/code&gt; : 릴리즈가 존재하지 않을 경우 새로 설치를 진행&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;--reuse-values&lt;/code&gt; : 마지막 릴리즈의 값을 재사용하고 새로운 값을 merge&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm list&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;설치된 릴리즈의 목록을 확인한다.&lt;/li&gt;&#10;&lt;li&gt;옵션&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;--deleted&lt;/code&gt; : 삭제된 릴리즈를 목록에 포함&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;--namespace&lt;/code&gt; : 지정한 네임스페이스의 릴리즈만을 확인&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm get [options] 릴리즈명&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;설치된 릴리즈의 상세 정보를 YAML 포맷으로 출력한다.&lt;/li&gt;&#10;&lt;li&gt;옵션&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;--version&lt;/code&gt; : 릴리즈의 버전&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;$ helm delete [options] 릴리즈명&lt;/code&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;설치된 릴리즈를 삭제한다.&lt;/li&gt;&#10;&lt;li&gt;옵션&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;purge&lt;/code&gt; : 릴리즈를 삭제하고 릴리즈명을 해제한다.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;</description></item></channel></rss>