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