1. 도커의 개념
2. 도커를 사용하는 이유
3. 도커의 사용법
4. build시 불필요한 반복 줄이기
5. Docker-compose
도커는 별도의 OS 설치가 필요없이 여러개의 격리된 가상화 환경을 구현할 수 있는 기술이다.
기존의 가상화 기술을 이용하여 만들어진 기술로 기존 가상화 기술은 가상화 환경마다 Guest OS를 둬야 했지만 도커는 리눅스 기반 기술로 별도의 Guest OS를 쓰지 않고 격리된 가상화 환경을 구현했다. 단 기본적인 도커 엔진이 올라가는 Guest OS 하나는 필요하다. 위 그림에서 나오는 Docker Engine은 리눅스 Guest OS이다. 즉 하나의 Guest OS (Docker Engine)만 두면 여러개의 격리된 가상환경을 구현할 수 있다.
위에서 언급한 격리된 가상화 환경이다. 도커 엔진 위에서 구동되는 격리된 시스템 자원 및 네트워크를 사용할 수 있는 공간이다. 위 그림에서 도커 엔진 위에 있는 하나 하나의 앱들이 도커 컨테이너라고 볼 수 있다.
컨테이너를 만드는 데 사용되는 읽기 전용(Read-only) 템플릿이다. 컨테이너 실행에 필요한 파일과 설정값 등을 포함하고 있는 도커파일을 만든 후 Dockerfile을 빌드 하여 이미지를 만든다. 이 이미지를 실행하면 만든 템플릿 대로 컨테이너가 만들어져 실행된다.
개발자들은 도커를 보통 개발환경을 세팅할 때 많이 사용한다. 우리가 서버를 돌리기 위해서는 먼저 환경이 갖춰져야 한다. 새로 컴퓨터를 샀다거나 또는 새로운 직원이 들어왔을 때 협업을 하기 위해 컴퓨터의 개발 환경을 모두 똑같이 만들어야 한다. 이를 위해 Node.js와 같은 런타임 환경 그리고 사용하는 언어의 버전, 데이터베이스, 수많은 node_modules를 버전을 맞춰서 설치해 줘야 한다. 이 환경을 도커 이미지로 만들어 놓는다면 개발환경 구축을 아주 쉽게 할 수 있다. 또한 만들어놓은 도커 이미지는 도커 클라우드 서버에 배포해 쉽게 다른 사람들과 공유가 가능하다. 도커 같은 프로그램이 없을 때는 환경을 구축하는 과정을 하나씩 캡처하고, 기록해서 방법을 정리해두기도 했다. 하지만 가이드 문서를 바탕으로 매번 이렇게 구축하는 것은 매우 번거로운 일이다. 이 과정을 간편하게 해주는 것이 바로 도커다.
기본적으로 Dockerfile에 어떤 이미지를 만들지 설정 코드를 적어놓고 그 Dockerfile 파일을 빌드해 docker 이미지를 만들고 그것을 실행해 실제 프로그램이 동작하는 컨테이너를 만드는 과정으로 사용한다.
Dockerfile은 이미지 생성을 위한 설정을 코드로 적어놓은 파일이다. 파일 이름을 그대로 DockerfileDockerfile은 이미지 생성을 위한 설정을 코드로 적어놓은 파일이다. 파일 이름을 그대로 Dockerfile이라고 지정한다. 아무 확장자도 지정할 필요없다. 도커 이미지를 만들기 위한 Dockerfile을 작성한다. 해당 Dockerfile에서 작성한 설정대로 이미지가 만들어진다.
이라고 지정한다. 아무 확장자도 지정할 필요없다. 도커 이미지를 만들기 위한 Dockerfile을 작성한다. 해당 Dockerfile에서 작성한 설정대로 이미지가 만들어진다.
FROM node:14
COPY ./index.js /myfolder/
WORKDIR /myfolder/
CMD node index.js
FROM 리눅스:최신 버전
이런 식으로 쓰면, 리눅스의 최신 버전이 깔린 컴퓨터가 한대 만들어진다. 이것은 다른 프로그램은 설치되어 있지 않은 상태의 리눅스이다. 도커에는 다른 사람들이 만들어놓은 필요한 것들이 이미 설치되어 있는 이미지도 있다.
예시로 FROM node:14
을 하면 node, npm, yarn이 모두 설치된 리눅스 컴퓨터가 하나 생기게 된다.
로컬에 있는 파일을 컨테이너 안에 복사할 때 쓰는 명령어이다. 위 예시 코드에서 COPY ./index.js /myfolder/
는 index.js
파일에 있는 모든 소스 코드를 가상 컴퓨터 안의 myfolder
폴더로 복사하여 해당 폴더에 저장한다는 의미이다. 이때 가상 컴퓨터 안에 myfolder
라는 이름의 폴더가 존재하지 않는다면 폴더가 자동으로 생성된다.
가상 컴퓨터가 만들어지면 이후 명령어를 실행할 작업 폴더를 지정해 준다.
도커 이미지가 빌드되는 과정에서 실행되는 명령어이다. RUN 실행할 명령어
와 같은 형식으로 실행한다.
실행할 명령어를 지정해 준다. CMD로 실행된 명령어는 docker run 이미지_아이디
명령어로 실제 도커 컨테이너를 띄울 때 실행된다.
정의한 Dockerfild로 이미지를 만들어주는 작업이다. 이를 build한다고 말한다. Dockerfile이 있는 경로에서 docker build .
를 실행한다.
빌드가 완료되면 이미지가 생성된 것이고, 이는 docker images
명령어로 확인해 볼 수 있다.
이렇게 한번 이미지를 만들어놓으면, 언제 어디서든 똑같은 환경의 가상 컴퓨터를 만들 수 있게 된다.
이제 만들어진 이미지를 실행해 실제 돌아가는 컨테이너를 만드는 작업을 해준다. docker run 이미지ID
를 실행한다. docker images
명령어로 알 수 있는 IMAGE ID를 사용하면 된다.
그 후 docker ps -a
를 통해 컨테이너가 제대로 만들어졌는지 확인해 보자.
-a
옵션은 종료된 컨테이너까지 모두 보여주는 옵션이다. -a
를 붙이지 않으면 현재 실행 중인 컨테이너만 보여준다.
위 그림처럼 실제 node 서버가 동작하는 것을 도커 터미널창에서 확인할 수 있다.
docker rm 컨테이너ID
명령어로 컨테이너를 삭제한다.
docker rmi 이미지ID
명령어로 이미지를 삭제한다.
.dockerignore
파일을 만들어 그 안에 복사를 방지할 파일명을 적는다.
예시
// .dockerignore
node_modules
위와 같이 적으면 node_modules 폴더는 도커파일 빌드시 실행되지 않는다.
docker exec -it 컨테이너_아이디 /bin/bash
명령어로 도커 컨테이너 내부에 접속할 수 있다. 접속하여 내부 log를 확인할 수 있다.
exit
명령어로 종료한다.
docker stop 컨테이너_아이디
로 실행 중인 컨테이너를 중지할 수 있다.
내 컴퓨터의 포트와 도커 컨테이너에서 실행 중인 프로그램의 포트를 연결해 주는 작업을 알아보자.
docker run -p 8000:3000 이미지_아이디
이렇게 작성하여 실행할 컨테이너를 내 컴퓨터의 포트와 연결해줄 수 있다. 내 컴퓨터의 8000 포트와 컨테이너의 3000번 포트를 연결하여 localhost:8000
으로 요청시 자동으로 도커 컨테이너의 3000번 포트로 요청이 가게 된다.
Docker는 build를 할 때, Dockerfile
을 보면서 명령어를 한 줄씩 실행하며 build를 진행한다. 이때, 기존에 존재하는 image와 비교하여 소스코드 상에 변경된 점이 없으면 이전 build시에 생성해둔 캐시를 가져와 사용하고, 아니라면 그 부분부터 명령어를 실행해 모두 새롭게 build 한다. 즉 소스코드가 변경되면 COPY
부분부터 build하는 것이다.
다음 Dockerfile
을 보자
// Dockerfile
FROM node:14
WORKDIR /myfolder/
COPY . /myfolder/
RUN yarn install
CMD yarn dev
위 코드는 매번 빌드시마다 yarn install
을 실행한다. 소스코드만 변경하여 해당 부분만 새롭게 빌드해주면 되는데 매번 빌드할 때마다 yarn install
을 실행하여 모듈을 설치해준다는 것은 상당히 비효율적이다. 따라서 Dockerfile을 다음과 같이 고쳐준다.
// Dockerfile
FROM node:14
WORKDIR /myfolder/
COPY ./package.json /myfolder/
COPY ./yarn.lock /myfolder/
RUN yarn install
COPY . /myfolder/
CMD yarn dev
위와 같이 써주면 RUN yarn install
까지는 캐시에서 저장한 것을 불러와 build하지 않게 되고 COPY
부분부터 변경된 소스코드만 build하여 적용해줄 것이다.
Docker-compose
란 복수 개의 컨테이너를 실행시키는 도커 애플리케이션을 정의하기 위한 툴이다. 기본적으로 YAML 파일
을 사용하여 애플리케이션의 서비스를 구성할 수 있다. 즉 YAML 파일
로 여러 개의 docker 내부 속성을 설정하고 YAML 파일
을 실행시켜 docker를 일괄적으로 한 번에 실행시킨다. 확장자는 .yml 이나 .yaml 둘 다 사용 가능하다.
docker-compose.yaml
파일은 version
, services
, volumes
, networks
를 정의할 수 있다. 여기서는 먼저 services
만 정의해 보겠다.
// docker-compose.yaml
version: "3.7"
services:
my-backend:
build:
context: .
dockerfile: Dockerfile
ports:
- 3000:3000
my-database:
build:
context: .
dockerfile: Dockerfile.mongo
ports:
- 27017:27017
services
정의는 각각의 컨테이너에 적용되는설정을 포함하고 있다. services
내부에 my-backend
와 my-database
를 정의해 주었다. 변수명과 같은 것으로 다른 변수명으로 정의해 주어도 상관없다. services
내부에 정의된 요소는 다음과 같다.
Dockerfile
을 포함하는 디렉토리 경로 또는 git repo의 urlDockerfile
을 대체하는 파일을 지정ports
정의는 Host OS와 컨테이너의 포트를 바인딩 시켜준다. 왼쪽이 Host OS의 포트이고 오른쪽이 컨테이너의 포트이다. 예를 들어 위 코드는 컨테이너의 노출된 포트 3000을 Docker Host 컴퓨터(Linux VM)의 포트 3000에 전달한다.
yaml 파일은 띄어쓰기로 설정을 구분하므로 띄어쓰기에 민감하다. 주의하자!
docker-compose.yaml
이 있는 경로로 이동하여 터미널 창에 docker-compose build
명령어를 실행한다. 이렇게 하면 docker-compose
설정한대로 여러개의 이미지를 만들 수 있다.
docker-compose up
명령어를 실행하여 빌드된 여러 이미지를 한번에 실행할 수 있다.
원래는 로컬에 있는 파일을 수정할 때마다 docker-compose build
와 docker-compose up
명령어를 차례대로 수행하여 빌드부터 실행을 모두 해주어야 한다. 하지만 volumes를 이용하면 매번 빌드를 다시 해줄 필요 없이 변경사항을 컨테이너에 적용할 수 있다.
version: '3.7'
services:
my-backend:
build:
context: .
dockerfile: Dockerfile
volumes:
- ./index.js:/myfolder/index.js
- ./email.js:/myfolder/email.js
ports:
- 4000:4000
my-database:
image: mongo:5
ports:
- 27017:27017
위 코드에서 volumes
라고 돼있는 부분이 로컬 파일과 컨테이너를 동기화 설정을 해주는 부분이다. 좌측에 있는 파일(local에 있는 파일
)에 변화가 생기면 우측(docker 컨테이너 내부에 동기화된 파일
)도 변경시켜주는 역할을 한다.
- ./index.js:/myfolder/index.js
콜론을 기준으로 좌측은 local에 있는 파일을, 우측은 docker 컨테이너 내부에 있는 파일을 가리킨다.