JUINTINATION
도커(Docker) 가볍게 입문해보기 - 3 본문
지난 도커(Docker) 가볍게 입문해보기 - 2에서 이어지는 내용이며 해당 글은 이 링크로 들어가면 확인할 수 있다. 지난 글에서 언급했듯이 이 스터디는 학교 선배가 작성한 강의 자료를 참고하였으며 ETRI에서 대여한 관련 책과 추가로 대여한 다른 책을 참고했다.
docker commit & docker diff
docker commit 명령어는 컨테이너 변경사항을 이미지 파일로 생성하는 역할을 한다. 예를 들어 ubuntu 이미지에서 아래 과정을 수행한다고 가정하자.
- example-directory라는 디렉토리를 생성한다.
- example-directory에 test.sh라는 파일을 생성한다. 이 쉘 스크립트 파일은 'hello world'라는 문자열을 출력할 수 있어야 한다.
기본적인 ubuntu 패키지 매니저 update, upgrade를 진행한다.
이 과정을 commit-test 컨테이너에서 진행했는데 나는 지난번에 연습하면서 해당 컨테이너를 이미 만들었기 때문에 $ docker rm commit-test
커맨드를 실행하여 해당 컨테이너를 지우고 시작했으며 $ apt-get update & apt-get upgrade
명령어는 시간이 너무 오래 걸리기 때문에 생략했다.
이 상태에서 새 터미널 창을 열고(맥 os의 경우 command + n
를 통해 새 터미널 창을 열 수 있다.) 아래와 같이 docker diff (컨테이너 이름 혹은 id)
명령어를 실행하면 아래와 같이 로그들이 나오는 것을 볼 수 있다.
$ apt-get update & apt-get upgrade
커맨드까지 실행했으면 훨씬 많이 나왔을 것이다. 아무튼 $ docker diff commit-test
커맨드의 실행 결과를 보면 앞에 A라는 플래그가 있는것을 볼 수 있다. 이 과정에서는 나오지 않았지만 C, D라는 플래그도 존재한다. 이 플래그들은 사용한 도커이미지를 기준으로 변경사항들을 의미하며 각각의 플래그는 아래 의미를 가진다.
- A : 추가된파일
- C : 변경된파일
- D : 삭제된 파일
이제 docker commit 을 사용해서 위 과정을 진행한 컨테이너를 이미지화 해볼것이다. docker commit의 기본 사용법은 아래와 같다.
docker commit <옵션> <컨테이너 이름 혹은 id> <이미지이름>:<태그, 생략시 latest로 치환>
commit 옵션 중 사용해볼 것은 -a와 -m 옵션이다.
- -a : 커밋을 진행한 사람
- -m : 커밋메세지
docker commit을 사용하기 위해 우선 컨테이너에서 나와 종료시킨다. 그 후 docker commit 명령어를 사용해준다. 이미지 생성시 태그가 있는 경우, 없는 경우 모두 생성해본 뒤 방금 전에 생성한 이미지를 grep 명령어를 사용해 출력해본다.
이후 $ docker run -it --name containerbycommit imagebycommit
커맨드를 실행하여 해당 컨테이너를 실행한다. 물론 나는 지난번에 연습하면서 해당 컨테이너를 이미 만들었기 때문에 $ docker rm containerbycommit
커맨드를 실행하여 해당 컨테이너를 지우고 시작했다. 이후 test.sh
의 내용을 sed
명령어를 이용하여 변경하고 확인해보자.
이후 다른(혹은 새로운) 터미널을 열고 docker diff 명령어를 사용하고 결과를 보면 아래와 같이 C 플래그와 함께 로그가 출력되는 것을 볼 수 있다.
$ rm test.sh
커맨드를 실행하여 test.sh
파일을 삭제한 후에 다른(혹은 새로운) 터미널을 열고 docker diff 명령어를 사용하고 결과를 보면 아래와 같이 D 플래그와 함께 로그가 출력되는 것을 볼 수 있다.
Dockerfile
만약 우분투에 git
, gcc
가 설치된 상태의 이미지가 필요하다고 가정을 하자. 위에서 본 docker commit 명령어를 이용해서 컨테이너 자체를 이미지로 변경하는 방법이 생각났다면 이런 방법에서의 단점은 명확하다.
- 패키지 설치를 일일히 설치해야하며 이미지에 특정 코드를 불러와야하는 경우, 골치아프다.
- 만약 이미지를 실수로 삭제한다면 다시 컨테이너를 만들고 다시 이미지로 만드는 과정을 거쳐야한다. 그리고 혹시라도 많은 명령어를 사용하여 이미지를 만들었다면 그 명령어들을 모두 기억할 수 있는 확률도 매우 적을 것이다. 이 뿐만아니라 과정도 꽤 복잡하다.
이러한 단점을 해결해줄 수 있는 것이 바로 Dockerfile이다. Dockerfile 문법에 대해 알아보기 전에 전반적인 Dockerfile 흐름을 살펴보자.
간단하게 apache2를 설치하고, 웹페이지 하나를 호스팅 하는 실습을 진행해 볼 것이다. 자신이 실습하고자 하는 디렉토리에 Dockerfile 이라는 파일을 생성한다(확장자 없음). 참고로 소스코드는 dockerfile-scratch에 있다.
다음은 내가 작성한 Dockerfile이다.
FROM ubuntu
LABEL maintainer="juintination"
RUN apt-get update && apt-get upgrade -y && apt-get install vim git apache2 -y
COPY ./index.html /var/www/html/index.html
ADD ./foo.js /var/www/html/foo.js
WORKDIR /var/www/html
EXPOSE 80
CMD ["-D", "FOREGROUND"]
ENTRYPOINT ["apachectl"]
다음은 내가 작성한 실습용 foo.js와 index.html 파일이다. Dockerfile과 동일한 디렉토리에 있어야 한다.
// foo.js
const exampleAlert = () => {
alert("example alert")
}
window.onload = () => {
const element = document.getElementById('jsloading');
element.innerText = "Javascript Loaded!"
}
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="./foo.js"></script>
<title>Document</title>
</head>
<body>
<h1>This webpage is hosted from docker container</h1>
<p style="color: blue;">Dockerfile from scratch</p>
<p id="jsloading">Wait for javascript loaded</p>
<button onclick="exampleAlert()">Example Button</button>
</body>
</html>
Dockerfile을 이미지로 만들기 위해서는 docker build라는 명령어를 사용하게 된다. 사용 방식은 아래와 같다.
docker build (옵션) (Dockerfile경로)
대표적인 옵션으로는 -t, -f가 있다
- -t : 이미지의 태그를 지정할때 사용한다.
- 필수 권장 옵션이며 아래와 같이 사용자 명을 같이 기재할 수 있다.
- Docker hub에 이미지를 올리기 위해서는 사용자 명을 꼭 붙여야한다.
docker build -t imagetag .
docker build -t hoplin/imagetag .
- -f : 기본적으로 도커엔진은 지정한 Dockerfile 경로에서 Dockerfile이라는 파일을 찾아서 이미지를 빌드한다.
- 하지만, 필요에따라 다른 이름의 도커파일을 생성해야할 수도 있다
- 예를 들어 개발 환경 도커를 위해 Dockerfile.dev와 같이 이름짓는 경우에 -f 옵션을 사용해서 도커파일의 이름을 지정해줄 수 있다.
docker build -f Dockerfile.dev -t imagetag .
터미널을 새로 열어, Dockerfile이 있는 디렉토리로 이동한다. 그 후 docker build 명령어로 이미지를 만들고 컨테이너를 실행한다. 명령어를 작성하기 전에 아래 조건을 생각해보자.
- 컨테이너 포트 80번은 호스트 머신의 9100번 포트에 바인딩 되어야 한다. 어떻게 해야할까?
- -p 옵션을 9100:80로 설정해야 한다.
- 컨테이너 실행 옵션은 Attach Mode, Detach Mode중 무엇이 더 알맞은 선택일까?
- 웹서버이므로 콘솔을 볼 필요 없이 실행이 목적이기 때문에 detach 모드로 실행한다.
$ cd (실습하고 있는 디렉토리)
$ docker build -t imagefromdockerfile .
$ docker run -d --name mycontainer -p 9100:80 imagefromdockerfile
위의 커맨드를 모두 실행했다면 localhost:9100에 접속하면 다음과 같은 화면을 볼 수 있을 것이다.
Dockerfile 문법
명령어 | 설명 |
FROM | 베이스 이미지 지정, 여러 개 중첩 가능 |
WORKDIR | 작업 디렉터리 설정, 컨테이너 실행 시 바로 해당 경로로 이동 |
RUN | 명령어 실행, shell command |
CMD | 컨테이너 실행 명령 |
LABEL | 라벨 설정 |
EXPOSE | 컨테이너의 트래픽을 Listening하는 포트 지정, 기본 TCP |
ENV | 환경 변수 설정 |
ADD | 파일 및 디렉터리 추가 |
COPY | 호스트의 디렉터리나 파일을 이미지 파일 시스템으로 복사 |
ENTRYPOINT | 이미지를 컨테이너로 띄울 때 항상 실행돼야 하는 명령 |
VOLUME | 데이터를 존속시킬 수 있는 볼륨 지정 |
ARG | docker build 명령어에서 -build-arg 옵션을 넘길 수 있는 인자 설정 |
SHELL | 기본 셸 설정 |
더 자세한Dockerfile 문법은 여기에서 "Dockerfile 문법"을 참고하자.
결론
여기서부터가 도커의 진짜 진짜 시작이 아닐까 생각이 든다. 확실히 어려워지고 더 깊게 들어가면 힘들 것 같다는 생각이 들었다. 나머지 더 딥한 내용들은 강의 자료의 Week4부터 보면 되는데 필요할 때마다 들어가서 보는 방향으로 가야할 것 같다.
스퍼트 프로젝트를 완성해서 Dockerizing까지 완료하는 그날까지..
'StudyNote' 카테고리의 다른 글
도커(Docker) 가볍게 입문해보기 - 4 (0) | 2024.02.03 |
---|---|
간단한 Express 프로젝트 Dockerizing 해보기 (1) | 2024.02.01 |
도커(Docker) 가볍게 입문해보기 - 2 (3) | 2024.01.26 |
Express.js와 nodemon (0) | 2024.01.23 |
Express.js와 passport-local을 사용한 로그인 테스트 (0) | 2024.01.21 |