도커 이미지
docker create <이미지이름>
Dockerfile
도커 이미지를 만들기 위한 설정 파일. 도커 컨테이너가 어떻게 행동해야 하는지 대한 설정 정의.
# 베이스 이미지 명시
FROM baseImage
# 추가로 필요한 파일들을 내려받음
RUN command
# 컨테이너 시작 시 실행할 명령어를 명시한다.
CMD ["executable"]
FROM 이미지 생성 시 기반이 되는 이미지 레이어 명시. <이미지 이름>:<태그> 형식으로 작성한다.
RUN 도커 이미지가 생성되기 전에 수행할 셸 명령어
CMD 컨테이너가 시작됐을 때 실행할 실행 파일 또는 셸 스크립트. 이 명령어는 도커 파일 내에서 한번만 사용 가능.
이미지 빌드하기
docker build . 해당 디렉토리에 Dockerfile을 찾아 도커 클라이언트에 전달한다.
docker run -it <이미지 ID>빌드한 이미지를 실행한다.
이미지에 이름 부여하기
docket build -t 도커ID/프로젝트:버전 .
docker build -t smaivnn/hello:latest .
-t tag의 약자
이제 docker run -it smaivnn/hello로 실행 가능하다.
도커로 node.js 어플 실행하기
파일 생성
우선 Dockerfile과 package.json 그리고 server.js를 생성한다.
package.json에 dependencies에 express와 같은 install해야 하는 의존성을 적는다. 이 때 실제로 install하여 node_modules를 생성할 필요는 없다. 이유는 다음과 같다.
도커란? 파트에서 기재하였듯이 도커 이미지가 프로그램을 실행하는 데 필요한 설정이나 종속성을 갖고 있고, 이런 이미지를 이용해 컨테이너를 생성하는 것이다. 그리고 생성한 도커 컨테이너를 이용해서 프로그램이 실행되기에 로컬에 node_modules가 있을 필요 없이 도커 컨테이너가 이를 갖고있다.
#Dockerfile
# node:10은 버전이다. <https://hub.docker.com/_/node/tags?page=1> 을 참고해서
# slim, latest등을 사용할 수 있다.
FROM node:10
# 이후부터는 아래에서 별도 설명
WORKDIR /usr/src/app
COPY package.json ./
RUN npm install
COPY ./ ./
CMD ["node", "server.js"]
WORKDIR /usr/src/app 우선 WORKDIR은 컨테이너 내부의 경로이다. 즉, 컨테이너 내부에서 작업 디렉토리를 설정하는 명령어이다. 이후의 명령어들이 실행될 기본 디렉토리를 설정하는 것인데, 사용하는 이유는 다음과 같다.
- 파일 경로 간소화 : 이후의 파일 경로 지정 시 절대 경로를 반복하지 않고 간소화된 형태로 사용 가능하다. 가독성의 향상과 유지보수의 용이함이 있다.
- 안정성과 일관성 : 특정 디렉토리를 작업 디렉토리로 설정하므로 해당 디렉토리 내에서 모든 작업이 수행된다. 디렉토리 밖에서 실수로 파일을 수정, 삭제 하는 오류 방지가 가능하다.
- docker 이미지 구조화 : **WORKDIR**을 사용하여 작업 디렉토리를 설정하면, 해당 디렉토리 내에 필요한 파일과 폴더들만 포함하여 Docker 이미지를 구성할 수 있다. 이로 인해 이미지 크기가 줄어들고, 필요하지 않은 파일이나 디렉토리가 포함되지 않도록 관리할 수 있다.
만약 WORKDIR을 사용하지 않고 파일과 폴더를 섞이게 두면 어떻게 될까?
- 기본적으로 root에 생성이 된다. 그러다가 파일과 폴더가 섞일 경우, COPY 지시자로 복사한 파일, 폴더가 이름이 같다면 원래 파일에 덮어 씌우게 된다.
- 한 폴더에 있으면 복잡하다.
이후 실행되는 COPY와 RUN 은 작업 디렉토리를 기준으로 파일을 복사하고 실행한다.
copy이후 run의 이유
COPY package.json ./
RUN npm install
아래 copy ./ ./이 상단에 오고, package.json을 먼저 복사하지 않을 경우 npm install을 진행하며 모듈 상태가 변경되지 않아도 모두 다운로드 받는 불필요한 자원 낭비가 발생한다. 따라서 package.json에 대해서 copy를 하고 만약 변화가 없다면 캐시(cahce)를 이용해 이 과정을 생략하는 효과를 기대한다.
COPY ./ ./ 는 나머지 모든 파일을 복사해오는 역할을 한다. 이미지 안에는 기본적으로 server.js라던가 package.json같은 파일은 존재하지 않는다. 따라서 이미지로 컨테이너를 만들 때는 컨테이너에 넣어주어야 하며 그것을 위한 카피이다.
docker run
docker run을 진행해서 애플리케이션 포트를 열 때 아래와 같이 포트 매핑을 진행해야 한다.
docket run -p <로컬 로스트 포트> : <컨테이너 속 포트> <이미지 이름>
ex) docker run -p 5000:8080 <이미지 이름>
그 이유는 로컬 호스트의 포트와 컨테이너 안의 포트가 나뉘어 있어서 이 둘을 연결해야 하기 때문이다. -p 옵션으로 둘을 매핑할 수 있다. build후 실행한다면 localhost:5000으로 컨테이너 속 포트로 접속할 수 있으며 성공적으로 node로 작성한 ‘/’화면이 출력 될 것이다.
자원 낭비
소스 코드를 변경할 때 마다 이렇게 계속해서 build하고 run을 반복하는 행위는 당연하지만 리소스 소모가 크다. 이를 도커 볼륨을 통해 해결할 수 있다.
Docker volume
지금까지는 로컬의 파일을 도커 컨테이너로 copy하는 방식을 진행하였다.
하지만 볼륨을 이용할 경우 도커 컨테이너로 하여금 로컬의 파일을 매핑하여 참조하는 방식을 사용한다.
이는 파일을 복사하지 않고 도커 컨테이너에서 로컬 호스트의 디렉터리의 파일을 참조하므로 소스를 변경해도 다시 COPY를 사용해 이미지를 빌드 할 필요가 없다. 즉, 개발 생산성이 높아진다.
사용법
docker run -p 5000:8080 -v /usr/src/app/node_modules -v $(pwd):/usr/src/app <이미지 아이디>
docker run -d -p 5000:8080 -v /usr/src/app/node_modules -v $(pwd):/usr/src/app <이미지 아이디>
ex)
docker run -p 5000:8080 -v /usr/src/app/node_modules -v /usr/src/app/node_modules -v /c/Users/meoro/OneDrive/Desktop/WebProgramming/nodejs-docker-app:/usr/src/app smaivnn/node-app
1번 2번 코드 공통적으로 우선, /usr/src/app/node_modules 이 부분은 로컬 호스트 디렉터리에는 node_modules가 없으므로 컨테이너에서 참조하지 말라고 지정하는 부분이다.
$(pwd)는 현재 작업 중인 디렉터리의 절대 경로를 뜻한다. 가령 예를 들어 터미널에서 pwd를 실행했을 때 나의 경로는 다음과 같다.
$ pwd
/c/Users/meoro/OneDrive/Desktop/WebProgramming/nodejs-docker-app
그러면 이를 반영한 경로는 아래와 같이 된다.
*해당 명령어를 길게 쓰라는 것이 아니다. 경로 예시를 보여주는 것일 뿐, $(pwd)명령어, 윈도우 환경에서는 %CD%를 사용한다.
-v /usr/src/app/node_modules -v /c/Users/meoro/OneDrive/Desktop/WebProgramming/nodejs-docker-app:/usr/src/app <이미지 아이디>
1번 코드는 도커 볼륨을 사용해서 애플리케이션을 실행하는 코드이다. 컨테이너가 실행되고 코드가 실행되면 애플리케이션이 실행된다.
2번 코드의 -d옵션은 detach의 약자로 컨테이너를 실행한 후에 컨테이너 ID만 출력하고 컨테이너에서 나오는 명령어로 백그라운드에서 컨테이너를 실행시키고 원래 터미널 상태로 돌아온다.
** window 환경에서 도커 볼륨이 적용되지 않는 사례가 있다. 나도 그렇다. 이때 해결 방법은 두가지이다.
1.
docker run -d -p 5000:8080 -v /usr/src/app/node_modules -v “$(pwd)/server.js:/usr/src/app/server.js” smaivnn/node-app
와 같이 마운트 할 앞 경로 전체를 큰 따옴표로 감싸주고, 앞쪽에는 /${pwd}/server.js 를 적어서 파일을 명시해주고, 뒤쪽에도 /usr/src/app/server.js로 파일을 명시해준다.
2. 우분투 터미널을 사용한다.
우분투 터미널을 사용하면 잘 실행 된다…
'Infra' 카테고리의 다른 글
[Docker] compose, 개발과 운영 환경 (0) | 2023.07.31 |
---|---|
[Docker] docker 개념 잡기, 명령어 (0) | 2023.07.26 |
[AWS] aws 리소스 개념 잡기 (0) | 2023.05.15 |