환경변수
- 도커 컨테이너에 호스트 운영체제의 것이 아닌 컨테이너의 호스트 명 같은 환경변수가 존재한다. 이를 조작하여 유연한 이미지 생성이 가능하다.
- 애플리케이션에서 사용할 기본값 외의 환경변수의 값을 --env key=value로 지정할 수 있다.
$ docker rm -f web-ping
$ docker container run --env TARGET=google.com diamol/ch03-web-ping
dockerfile 작성하기
- 애플리케이션 패키징을 위한 스크립트로, 일련의 인스트럭션으로 구성된다.
FROM diamol/node #node.js가 설치되어있음
ENV TARGET="blog.sizeyed.com"
ENV METHOD="HEAD"
ENV INTERVAL="3000"
WORKDIR /web-ping
COPY app.js
CMD ["node", "/web-ping/app.js"] #node명령어로 app.js를 실행시킨다.
- FROM으로 시작점으로 지정할 이미지를 지정한다.
- ENV로 환경변수를 설정한다.
- WORKDIR로 컨테이너 이미피 파일 시스템에 디렉토리를 만들고 작업을 진행한다. 즉, 리눅스에선 /web-ping디렉을 윈도우에선 C:\web-ping디렉을 만든다.
- COPY는 원본경로 복사경로 처럼 작업 디렉토리로 파일을 복사한다. 복사경로 미지정시 작업디렉토리로 간다.
- CMD는 도커가 이미지의 컨테이너 실행 시 실행시킬 명령을 지정하는 인스트럭션이다.
컨테이너 이미지 빌드하기
- 이미지 빌드를 위해서 이미지이름, 패키징 파일의 경로를 지정해야한다. --tag로 이름을 지정하고 파일 경로는 .로 현재디렉토리를 가리키자.
- build 명령어를 실행하면, dockerfile 스크립트의 인스트럭션이 차례로 실행되며 결과가 출력된다.
$ docker image build --tag web-ping .
$ docker image ls w*
$ docker container run -e TARGET=docker.com -e INTERVAL=5000 web-ping
추가적으로 아직 컨테이너와 이미지 개념이 햇갈리는데(아래를 보면 컨테이너는 없는데 이미지만 많은 부분에서 혼동 발생. 이미지는 컨테이너 위에서만 돌아가는 것이 아닌가?), 우선 둘은 다른 것이고 컨테이너는 여러 이미지를 포함하는 환경정도로 이해하고 넘어가겠다. 이미지는 iso같이 이미지일 뿐이고, 이를 실행할 때만 컨테이너 위에서 실행하나보다!
도커 이미지와 이미지 레이어
- 도커 이미지에는 패키징한 모든 파일(컨테이너의 file system을 형성할 예정), 자신의 메타 데이터(이미지의 빌드정보 등)들이 존재한다.
$ docker image history web-ping
- CREATED BY 부분은 해당 레이어를 구성한 dockerfile 스크립트의 인스트럭션인데, 모든 인스트럭션은 레이어와 1:1 관계를 가진다.
- 도커 이미지는 도커엔진 캐시에 물리적으로 저장된 다양한 이미지 레이어(인스트럭션)들이 모여 저장되어 서로 공유된다. Node.js 컨테이너 여러개를 실행하면 Node.js 런타임 레이어를 공유한다. dockerfile 인스트럭션의 FROM diamol/node가 의미하는 바가 이것이다. 즉, 기반 레이어 위에 레이어를 추가하고 기반 레이어를 공유함으로써 전체 용량을 줄일 수 있다.
$ docker image ls
- 각각 node.js때문에 용량이 많아보이지만, 실제로는 하나의 node.js공간을 기반레이어로서 공유하고 있다.
- 아래의 명령어로 실제 사용된 디스크 용량을 확인할 수 있다.
$ docker system df #
(왜 난 별 차이가 없지 ㅋㅋㅋ 다 더해보면 716.9인데 633으로 뜨는 것을 보니 공유되고 있긴 한가보다! 다만 다른 실행되고 있는게 많은 듯!)
- 가장 중요한 것은, 기반 레이어가 수정되면 공유되는 다른 이미지에 영향을 미치기에 공유되는 레이어는 수정 불가능해야한다.
이미지 레이어 캐시를 이용한 dockerfile 스크립트 최적화
- 파일을 약간 수정한 후 다시 빌드하면 변경되지 않은 부분은 캐시된 레이어를 재사용한다. 즉, 인스트럭션의 결과가 이전과 같다면(해시값을 통해 비교) 이전에 캐시된 레이어를 사용하여 인스트럭션 실행 낭비를 줄일 수 있다.
- 한번 인스트럭션이 실행되면 그 다음 인스트럭션은 캐시에 있더라도 모두 실행된다. 즉, 잘 수정하지 않는 인스트럭션이 앞으로 와야 최적화가 가능하다.
FROM diamol/node
CMD ["node", "/web-ping/app.js"]
ENV TARGET="blog.sixeyed.com" \
METHOD="HEAD" \
INTERVAL="3000"
WORKDIR /web-ping
COPY app.js
최적화 이후 마지막을 제외하고는 모든 레이어를 캐시에서 재활용한다.
연습문제
- 도커 허브에 공유된 diamol/ch03-lab의 ch03.txt를 수정하고, 해당 이미지를 dockerfile 없이 빌드하라
$ docker container run -it --name ch03lab diamol/ch03-lab
# echo jimo >> ch03.txt
# exit
$ docker container commit ch03lab ch03-lab-soln
$ docker container run ch03-lab-soln cat ch03.txt
- commit은 컨테이너의 변경된 내용으로 새로운 이미지를 만든다. 즉, 공유허브내의 ch03.txt를 변경하고 변경 내용을 새로운 이미지 ch03-lab-soln를 만들어서 실행시킨 뒤 ch03.txt를 출력시킨 것이다.