2장에선 패킹징한 도커 이미지를 활용했다면 이번에는 도커 이미지 만드는 방법을 배운다.
실습 예제에는 web-ping이라는 간단한 어플리케이션을 다루는데 이는 지정한 웹 사이트가 노출되는지 확인하는 기능을 한다.
docker container run
명령을 사용하면 로컬 컴퓨터에 없는 이미지를 내려받는 과정이 있었다.
docker image pull diamol/ch03-web-ping
해당 명령을 사용하면 원하는 이미지를 다운 받을 수 있다.
아니....
해당 문제는 단순히 docker desktop을 실행하니 되었다.
다시 문제로 돌아와서
내려받은 이미지의 이름은 "diamol/ch03-web-ping"이다.
해당 명령어에서 이해 해야하는 부분은 다음과 같다.
도커 이미지는 논리적으로 하나의 대상이라는 것이다. 그에 대한 예로 애플리케이션 스택 전체가 하나의 파일로 압축된 압축 파일 형태로 저장되는 것을 들 수 있다.
이미지 내려받는 과정을 보면
여러 건의 파일을 동시에 내려받는다. 이들 각각의 파일을 이미지 레이어라 한다. 도커 이미지는 물리적으로 여러 개의 작은 파일로 구성되어있다. 도커가 이 파일들을 조립하여 컨테이너의 내부 파일 시스템을 만든다.
docker container run -d --name web-ping diamol/ch03-web-ping
여기서 -d 는 컨테이너의 백그라운드에서 동작한다는 플래그이다. 해당 컨테이너는 네트워크 요청을 받지 않기 때문에 포트를 외부로 공개할 필요가 없다.
--name은 이전에 임의로 생성된 컨테이너 ID를 이용했던 것과 달리 컨테이너에 이름을 지칭할 수 있다. 우리는 web-ping이라는 것을 컨테이너에 붙인 것이다.
2장에서 배운 컨테이너의 상태 확인 명령어를 입력해보자.
docker container logs web-ping
blog.sixeyed.com으로 HTTP 요청을 반복적으로 보내고 있음을 알 수 있다.
응답 시간을 파악하는 것은 웹 사이트 동작 여부를 확인하는데 유리한 방법이다. 이를 환경변수 값에서 설정값을 읽어와 다양한 옵션을 설정할 수 있다.
환경 변수는 운영체제에서 제공하는 키-값 쌍이다. 윈도나 리눅스나 같은 방식으로 동작하며, 도커 컨테이너도 별도의 환경 변수를 가질 수 있다. (web-ping 이미지에도 환경 변수의 기본값이 포함돼 있다.)
docker rm -f web-ping
docker container run --env TARGET=google.com diamol/ch03-web-ping
아까와 달리 화면에 계속 본인다! 이유는 -d(--detach)옵션을 주지 않았기 때문이다.
그리고 보내는 사이트가 google.com으로 변경되었다.
web-ping 애플리케이션의 코드는 TARGET이라는 이름의 환경 변수 값을 찾는다. 원래 blog.sixeyed.com으로 설정되어 있으나 docker container run명령에서 --env 플래그를 이용해 다른 값을 지정할 수 있다. 즉 컨테이너마다 다른 환경 변수 값을 이용할 수 있다.
Dockerfile은 애플리케이션을 패키징하기 위한 간단한 스크립트이다. 일련의 인스트럭션으로 구성되어 있으며, 실행결과로 도커 이미지가 만들어진다.
이하는 web-ping 애플리케이션의 Dockerfile 스크립트이다.
FROM diamol/node
ENV TARGET="blog.sixeyed.com"
ENV METHOD="HEAD"
ENV INTERVAL="3000"
WORKDIR /web-ping
COPY app.js .
CMD ["node", "/web-ping/app.js"]
위에 대문자들을 소문자로 입력해도 상관없다.
FROM : 모든 이미지는 다른 이미지로부터 출발한다. 이 이미지는 diamol/node 이미지를 시작점으로 정한 것이다. 해당 이미지에는 web-ping 애플리케이션을 실행하는데 필요한 런타임인 Node.js가 설치돼 있다.
ENV : 환경 변수 값을 지정하기 위한 인스트럭션이다. [key]="[value]"로 지정되어 있는 것을 알 수 있다.
WORKDIR : 컨테이너 이미지 파일 시스템에 디렉터리를 만들고, 해당 디렉터리를 작업 디렉터리로 지정하는 인스트럭션이다. 리눅스와 윈도 컨테이너 모두 구분자로 /를 사용하기 때문에 리눅스 컨테이너에서는 위와 같이 사용하고, 윈도 컨테이너에서는 C:\web-ping 디렉터리를 만든다.
COPY : 로컬 파일 시스템의 파일 혹은 디렉터리를 컨테이너 이미지로 복사하는 인스트럭션이다. [원본경로][복사경로] 형식으로 지정하면 된다. 해당 경우에선 로컬 파일 시스템에 있는 app.js파일을 이미지 작업 디렉터리로 복사한 것이다.
CMD : 도커가 이미지로 부터 컨테이너를 실행했을 때 실행할 명령을 지정하는 인스트럭션이다. 여기서는 Node.js 런타임이 애플리케이션을 시작하도록 app.js를 지정했다.
cd ch03/exercises/web-ping
해당 명령어를 입력해 도커이미지를 빌드하기 위한 파일을 확인하라 했으나
ls를 입력했을 때 애초에 ch03이라는 디렉토리도 없다.
또한 책의 예시에선 C:\scm....경로인데 나는 scm도 없다.
자 해결해보자
여기에 있네? 근데 이걸 다운받아서 어디에 저장해놔야하지?
지금 판단으론 github와 연동이 안되어 문제가 생겼다 판단된다.
1장으로 다시 돌아가서
리눅스 서버에 도커 설치하기를 해보자.
이 문제는
https://askubuntu.com/questions/982029/unable-to-locate-package-have-i-done-something-wrong
이 사이트를 통해
이렇게 고쳤다.
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88
만료 되었다지만 일단 뭐 진행...
생각해보니 안해도 되자나ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 이미 앞서 해당 단계를 해야만 나타나는 화면을 보았기 때문이다. 한장 뒤에 github만 있는데 이것만 해도 되지 않을까?
아...아악
https://hyeo-noo.tistory.com/184
해당 사이트 참조하여 수정하려 했으나 막혔다.....
그래서 소스코드를 압축파일로 다운받아 해제하였다
그러면서 새로운 명령어도 배웠다.
docker container rm -f $(docker container ls -aq)
docker container rm -f $(docker image ls -f reference='diamol/*' -q)
각각 실습환경을 초기화 하는 것과 이미지가 차지한 디스크 용량을 회수할 때 사용하는 것이다.
다시 문제로 돌아와 화면에 해제한걸 저장하고 터미널로 그길로 들어갔다.
으하하하하하하
Dockerfile 스크립트 외에도 이미지의 이름, 패키징에 필요한 파일의 경로를 추가로 지정해 주어야 한다.
docker image build --tag web-ping .
를 실행하면 Dockerfile 스크립트로 이미지를 빌드하는 것이다.
근데
아하하하하 쉽게 안될 줄 알았지.
(방금 전 발생했던 문제로 돌아갔었음)
오오 된다...
이제 다시 문제를 풀어보자
여기서 --tag의 인자값은 이미지 이름이고, 이어진 인자는 Dockerfile 및 이미지에 포함시킬 파일이 위치한 경로이다.
도커에서는 이 디렉터리를 컨텍스트라고 한다.
build 명령을 입력하면 Dockerfile 스크립트에 포함된 인스트럭션이 차례로 실행되며 결과가 출력된다.
만약 build 명령에서 오류가 발생했다면
1. 도커 엔진이 정상적으로 동작 중인지 확인해야하며
2. 현재 작업 디렉터리가 정확한지 확인한다.
3. 마지막으로 build 명령을 정확하게 입력했는지 확인한다.
책에선 success~~가 나와야 성공적으로 빌드했다 하지만 나는 따로 출력되지 않았다.
다만
docker image ls 'w*'
을 실행했을 때 책과 같게 나왔으므로 넘어가려 함다.
해당 명령어는 web-ping 이미지를 확인할 수 있는 명령어이다.
docker container run -e TARGET=docker.com -e INTERVAL=5000 web-ping
을 실행하면 새로 빌드한 이미지로부터 컨테이너를 실행해 도커 웹사이트에 5초마다 요청을 보내는 것이다.
이 컨테이너는 foreground로 동작하므로 control+c를 통해 중지 시킨다. 그러면 애플리케이션이 종료되고 컨테이너도 종료된다.
도커 이미지에는 우리가 패키징에 포함시킨 모든 파일이 들어있다. 이들 파일은 나중에 컨테이너의 파일 시스템을 형성하며 이미지에는 자신에 대한 여러 메타데이터 정보도 들어 있다. 이 정보 중 이미지가 어떻게 빌드됐는지에 대한 이력도 포함되는데 이를 이용해 이미지를 구성하는 가레이어와 어떤 명령으로 빌드 됐는지 알 수 있다.
docker image history web-ping
이 이미지는 한 줄마다 한 레이어에 대한 정보가 출력된다.
여기서 CREATED BY 항목은 해당 레이어를 구성한 Dockerfile 스크립트의 인스트럭션이다. 이 인스트럭션과 이미지 레이어는 1대1관계를 갖는다.
도커 이미지는 이미지 레이어가 모인 논리적 대상이다. 레이어는 도커 엔진의 캐시에 물리적으로 저장된 파일이다.
굉장히 중요한 그림이다.
web-ping이미지는 diamol/node 이미지를 기반으로 하므로 기반 이미지의 모든 레이어를 포함한다. Dockerfile 스크립트의 FROM 인스트럭션의 의미가 바로 이것이다.
docker image ls
해당 명령어는 출력된 이미지 목록에서 각 이미지의 용량을 확인할 수 있다.
중요한 것은 이미지 목록의 SIZE 항목에 나오는 수치는 이미지의 논리적 용량이지 해당 임지가 실제로 차지하는 디스크 용량을 나타내는 것이 아니다.
이미지 저장에 실제 사용된 디스크 용량은
docker system df
를 통해서 확인 가능하다.
이미지 레이어를 여러 이미지가 공유한다면, 공유되는 레이어는 수정할 수 없어야 한다. 도커는 해당 레이어를 읽기 전용으로 만들어 두어 이런 문제를 방지한다. 이미지를 빌드하면서 레이어가 만들어지면 레이어는 다른 이미지에서 재사용될 수 있지만 수정될 수는 없다.
책에서 app.js를 수정하라 하였으나 나는 powershell로 vim을 사용할 수가 없어서 메모장을 켰다.
책은 구버전이라 그런가 출력되는 화면이 다른데, 핵심은 기존에 캐시된 레이어가 재사용되고 새로운 레이어가 만들어졌다는 것이다. (보면 걸린 시간이 짧아졌다.)
Dockerfile 스크립트의 인스트럭션은 각각 하나의 이미지 레이어와 1:1로 연결된다. 그러나 결과가 이전 빌드와 같다면 캐시된 레이어를 사용한다.
캐시에 일치하는 레이어가 있는지 확인하기 위해 도커는 해시값을 이용한다. 해시값은 Dockerfile 스크립트의 인스트럭션과 인스트럭션에 의해 복사되는 파일의 내용으로부터 계산된다. 기존 이미지 레이어에 해시값이 일치하는 것이 없다면 캐시 미스가 발생하고 해당 인스트럭션이 실행된다. 한번 인스트럭션이 실행되면 그다음에 오는 인스트럭션은 수정된 것이 없더라도 모두 실행 된다.(아 여기서 이해했다.)
그렇기 때문에 잘 수정되지 않는 레이어는 앞으로 오도록 배치해야한다.
FROM diamol/node
ENV TARGET="blog.sixeyed.com"
ENV METHOD="HEAD"
ENV INTERVAL="3000"
WORKDIR /web-ping
COPY app.js .
CMD ["node", "/web-ping/app.js"]
아까 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 .
최적화한것이다. CMD 인스트럭션 위치가 바뀌었는데 일단 해당 CMD는 FROM 뒤라면 어디에 놓아도 문제가 없다.
그리고 ENV도 여러개의 환경 변수를 정의할 수 있으므로 세 개의 ENV 인스트럭션을 하나로 합쳤다.
위의 사진은 최적화된 스크립트예제코드로 빌드한 것이다.
아까처럼 app.js를 수정한다면 마지막 단계만 바뀔 것이다.(이후에 다른 인스트럭션이 없기 때문에)
이번 장에서 중요한것은 두가지이다.
첫 번째는 Dockerfile 스크립트의 최적화다.
두 번째는 다른 환경에도 애플리케이션을 배포할 수 있도록 이식성 있는 이미지를 만드는 것이다.
이번 연습 문제는 Dockerfile 스크립트 없이 도커 이미지를 만드는 것이다.
도커 허브에 공유된 diamol/ch03-lab 이미지가 있고, 이 이미지 안에는 /diamol/ch03.txt 파일이 있다. 연습 문제는 이 파일 뒤에 나의 이름을 추가한 다음, 수정된 파일을 포함하는 새로운 이미지를 빌드하는 것이다. 다만 Dockerfile 스크립트를 이용할 수 없다.
자 먼저 실행을 하면 이렇게 되어있다. 이를 해결하기 위해 echo를 이용해 내용을 추가해주자.
이걸 이제 빌드 해야한다. 단 바뀐 내용을 적용해야한다. 해당 요청에 적합한 명령어가 뭐가 있을까?
두둥탁. commit이다.
응 이게 왜 안될까? 생각을 해보면 단순히 ch03-lab은 이미지이다. 원본은 수정되지 않았을 것이다. 나는 바뀐 것을 찾아야한다. 그렇다면 바뀐 것은 무엇일까?
그렇다 우린 NAMES에 있는 것으로 접근해야 하는 것이다.
자 이렇게 우린 바뀐 것을 확인할 수 있었다.