2020-3-17 도커이미지 만들기
도커
배경
- 도커는 계층화된 파일시스템(AUFS, BTRFS) 등을 이용해서 가상화된 컨테이너의 변경사항을 모두 추적하고 관리한다. => 특정 상태를 항상 보존.
- 가상머신은 격리된 환경을 제공해주지만, OS위에 또 다른 OS를 실행하므로 성능손실이 많다. 도커의 가상화는 운영체제를 가상화하는게 아닌 격리된 환경을 만들어준다.
이미지
- Docker에서 실제 실행되는것은 이미지가 아니다. 이미지는 추상적인 개념이고, 실행되는건 이미지를 기반으로 생성된 컨테이너이다.
- docker pull <imageName>을 통해 가져온다.
- docker ps -a 명령어를 통해 확신해보면 TAG가 <none>것들이 있다. 이 부분은 최종적인 이미지를 생성하는 과정에서 생성되는 중간이미지들이다.
컨테이너
- 실제로 실행되는 가상머신은 항상 컨테이너이다. 컨테이너란 격리된 환경에서 특정한 명령어를 싱행시켜주는 가상머신같은 무엇인가이다.
- 셸을 실행시키지 않아도 가상머신을 조작할 수 있다.
$docker run -i -t ubuntu:version /bin/bash
$root@id exit
$docker restart containerId
$docker attach containerId
- docker run명령어를 통해 /bin/bash셸로 들어간다.
- 컨테이너안에 들어가서 조작하다가 exit 명령어를 입력하면 컨테이너 밖으로 나오면서 컨테이너가 종료된다.
- docker restart를 하면 다시 실행한다. 하지만 bash shell로는 들어가지 않는다.
- docker attach명령어를 통해 shell안으로 다시 들어간다.
- docker run할때 –rm 플래그를 붙이면 컨테이너가 종료될때 자동으로 삭제하는 옵션이다.
버전관리 시스템과 도커
- 컨테이너와 이미지가 다르다고 했지만, 컨테이너를 변경하면 이미지는 어떻게 되는가? 아무런 변화없다. 도커이미지는 불변하는 저장매체이다. 하지만 이미지위에 무언가를 얹어서 새로운 이미지를 만들수는 있다. 컨테이너는 Mutable하다.
$root@id:/# apt-get install -y git
$docker diff id
$docker commit id image:name
- docker diff id를 하면 부모이미지와 자식이미지간의 파일시스템의 변경사항을 확인할 수 있다.
- docker commit을 하면 새로운 도커 이미지를 만들 수 있다.
이미지삭제
- 삭제하려는 이미지에서 하나라도 파생된 이미지가 있으면 삭제가 불가능하다. 따라서 관련된 컨테이너를 모두 종료해야한다.
- docker rm은 컨테이너를 삭제, docker rmi는 이미지를 삭제한느 명령어
Dockerfile
- 도커이미지를 만드는 3가지 방법
- pull 명령어
- docker commit으로 이미지 만들기
- Dockerfile 도커이미지 생성용 배치파일 사용하기
- Dockerfile은 특정 이미지를 출발점으로 새로운 이미지 구성에 필요한 일련의 명령어들을 저장한 파일
// Dockerfile
FROM node:10.19-alpine
MAINTAINER Jimmy KIM <jimmyjaeyeon@gmail.com>
RUN apk update && apk upgrade
RUN apk --no-cache add --virtual builds-deps build-base python
RUN mkdir app
# set app directroy as workdirectory
WORKDIR /app
# copy current file to app directroy
COPY package*.json ./
COPY .env ./
RUN ls /app
# npm module install
RUN npm install
RUN npm rebuild bcrypt --build-from-source
COPY . .
RUN npm run build
RUN ls
# run command npm start
CMD ["node", "dist/main"]
- from은 이미지를 어디서 가져오는지
- run은 직접 셸 명령어를 실행
- expose는 가상머신에 오픈할 포트지정.
- CMD : 컨테이너에서 실행될 명령어를 지정
- docker built -t . => -t를 이용해서 이름과 태그를 정할 수 있다.
$docker run -d -p 9999:80 name/tag
- -d플래그는 -i플래그와 반대로 백그라운드에서 실행시켜준다.
- -p플래그는 포트포워딩으로 :경계로 앞은 외부포트 뒤는 내부포트이다. Localhost:9999로 들어오는 포트를 80포트로 보내도록한다.
- node와 bcrpyt 이슈가 있어서 RUN apk –no-cache add –virtual builds-deps build-base python 명령어를 추가하였다.
- 실행은 됬지만 db connection이슈로 인해 동작하지 않았다.
데이터베이스 컨테이너 실행
- 기본적으로 도커는 격리된 환경에서 실행하기 때문에 옵션을 지정하지 않으면 다른 컨테이너의 존재를 모른다.
- 앱컨테이너에게 DB컨테이너를 알려주는 방법
- 데이터베이스 컨테이너를 실행하면서 컨테이너 이름을 붙인다.
- 앱 컨테이너를 실행할때 db컨테이너를 연결한다.
$ docker run --rm \
--name db \
-e POSTGRES_DB=djangosample \
-e POSTGRES_USER=sampleuser \
-e POSTGRES_PASSWORD=samplesecret \
postgres
// link app container to database container
$ docker run -it --rm \
-p 8000:8000 \
--link db \
-e DJANGO_DB_HOST=db \
-e DJANGO_DEBUG=True \
django-sample \
./manage.py runserver 0:8000
에러참조
- https://github.com/kelektiv/node.bcrypt.js/wiki/Installation-Instructions
느낀점
- 면접질문에 도커이미지를 어떻게 최적화를 시킬지? stateful vs stateless 컨테이너의 차이는 무엇인가? 컨테이너들끼리는 어떻게 통신을 할것인가? 여러개의 컨테이너를 돌릴때 로그를 하나로 모으기 위해서 어떻게 해야되는지? docker-compose version 2와 3의 차이는? 위의 질문들은 최근에 면접에서 받은 질문들이였다. 도커 이미지를 만들기만 해봤지 성능최적화나 기능들에 대한 차이는 고려를 안했었다. 이 부분을 이제 학습하자.
Reference
- https://blog.nacyot.com/articles/2014-01-27-easy-deploy-with-docker/
Written on March 17, 2020