Docker 를 알아보자 🐳

임철종·2022년 8월 18일
1
post-thumbnail

설문조사에서의 Docker

도커는 2021년 스택오버플로우 설문조사 기타 개발 도구 부문에서 Git 다음으로 2위를 차지하였을 만큼 많은 개발자들이 사용하고 있는 도구입니다.


76.5%의 사용자가 도커를 사랑하고 있고


29.7%의 개발자들이 도커를 사용해보고 싶어합니다.

도커란?

어플리케이션을 패키징 할 수 있는 툴

container 라고 불리는 하나의 작은 소프트웨어 유닛 안에 어플리케이션과 그에 필요한 시스템 툴, 환경설정 등 모든 dependency 를 하나로 묶어서 다른 서버나 다른 PC, 어디에서나 쉽게 배포하고 안정적으로 구동할 수 있도록 도와주는 툴이다.

기술이 발전함에 따라 어플리케이션을 구동하는데 많은 것들이 필요해졌다.
node.js 를 예로 들면 소스파일만 서버에 배포하는 것으로는 구동하는데 문제점이 있다.
npm, 환경설정, 디펜던시들, 환경변수 등 모든 것들을 설치하고 설정해야 하는데, 서버마다, PC 마다 모든 것들을 설치하고 설정하는 것은 번거롭고 오류가 발생하기도 쉽다.

이런 번거로움을 해결하기 위해 docker 가 탄생했다.

도커의 컨테이너에는 어플리케이션을 구동하는데 필요한 모든 것들을 담아 놓았다.

Docker vs VM (Virtual Machine)

Virtual Machine

VM 은 하드웨어 위에 vmware 나 VirtualBox 와 같은 하이퍼바이저 소프트웨어를 이용하여 가상 머신을 만드는 것이다.
한 운영체제 위에서 동일한 어플리케이션을 각각 고립된 다른 환경에서 구동하기 위해서는 이 VM 을 이용하여 어플리케이션을 구동해야 했다.
VM 은 각각의 운영체제를 포함하고 있기 때문에 Mac 위에서 사용하면 Window 와 Linux 를 동시에 구동할 수 있다.

하지만 VM 을 사용하면 운영체제를 포함하고 있기 때문에 굉장히 무겁고 컴퓨터의 리소스를 많이 사용하게 된다.

Docker's Container

Container 는 VM 에서 조금 경량화 된 컨셉입니다.
Container 는 하드웨어에 설치된 운영체제인 Host OS 에서 Container Engine 이라는 소프트웨어를 설치하면 각각의 고립된 container 를 만들어서 어플리케이션을 고립된 환경에서 구동할 수 있게 해줍니다.
container 는 운영체제를 포함하지 않고 container engine 이 설치된 host OS 를 공유한다.

container 가 구동되기 위해서는 container engine 이 필요하고 이 container engine 들 중에 가장 많이 사랑 받는 것이 Docker

Docker 101

구성요소

1. Dockerfile

무엇이 필요한지 적혀있는 파일
-> 설명서, 요리의 레시피

포함되는 것

  • 어플리케이션을 구동하기 위해 꼭 필요한 파일들
  • 프레임워크나 라이브러리 등 외부 디펜던시
  • 필요한 환경변수
  • 어떻게 구동하는지에 대한 스크립트

2. Image

dockerfile 을 이용해 만든, 변경이 불가능한 image 파일
-> 객체지향의 Class
템플릿 형태로 이미지를 만들어두고 그 이미지를 이용하여 실제로 어플리케이션이 동작하는 container 를 만들 수 있다.

특징

  • 어플리케이션을 실행하는데 필요한 코드, 런타임 환경, 시스템 툴, 시스템 라이브러리 등 모든 셋팅
  • 불변의 상태

3. Container

image 를 따라 만든 고립된 실행 환경
-> sandbox

  • image (class) 로 만들어진 instance 라고 볼 수 있다.
  • 파일을 만들거나 수정 가능하며 image 에는 영향을 끼치지 않는다.

정리

  • 동작하고 있는 어플리케이션을 캡쳐하여 템플릿 형태의 image 를 만들고 이를 이용하여 실제로 어플리케이션이 동작하는 각각의 컨테이너를 만든다.
  • image 는 객체지향의 class
  • container 는 class 로 만들어진 instance
  • container 는 수정 가능하며 image 에 영향을 끼치지 않는다.

배포

Git, Github 와 비슷한 방식으로 작동한다.

  1. 로컬 머신에서 image 파일을 만든다.
  2. github 와 같은 역할을 하는 container registry 에 image 를 push 한다.
  3. 필요로 하는 서버나 PC 에서 image 를 pull 하여 그대로 실행한다.
    docker 와 같은 container engine 을 필요로 한다.

실습 (node.js)

1. 운영체제에 맞는 docker 설치 🐳

2. node.js 프로젝트 생성 👨‍💻

  1. npm init -y 프로젝트 초기화

  2. npm install express express 설치

  3. index.js

    const express = require('express')
    
    const app = express()
    
    app.get('/', (req, res) => res.send('This is Docker 🐳'))
    
    app.listen('8080', () => console.log('✅ Server is running'))
    

3. Dockerfile 생성 📝

Dockerfile reference

Dockerfile 포맷

Dockerfile 은 기본적으로 다음과 같은 명령문이 겹겹이 쌓인 layer 형태로 구성되어 있다.

# 주석 (Comment)
명령어 (INSTRUCTION) 인자 (arguments)

각 명령어는 모두 대문자로 작성하며 여러개의 인자가 따라올 수 있다.
주석 또한 달 수 있다.

FROM

base image
node 의 경우 미리 만들어 둔 node base image 가 있다.
FROM <base image:version>
: 뒤에 오는 숫자는 버전을 의미하며, alpine 은 최소의 linux 버전을 말한다.

  • ubuntu 최신 버전을 base image 로 사용
    FROM ubuntu:lastes
  • node.js 16 버전, linux 기반을 base image 로 사용
    FROM node:16-alpine

WORKDIR

WORKDIR 명령어는 리눅스 명령어 cd 처럼 container 상에서 작업 디렉토리를 전환하기 위해 사용한다.
WORKDIR <경로>

  • 루트 디렉토리의 app 폴더 안의 모든 파일을 카피한다.
    WORKDIR /app

COPY

COPY 명령어는 host PC 의 파일을 Docker image 의 파일 시스템으로 복사하기 위해 사용합니다.
절대경로와 상대경로를 모두 사용할 수 있으며, 상대경로를 사용하는 경우 이전에 WORKDIR 명령어로 전환된 현재 위치를 고려해야 한다.

Dockerfile 에서 명령어를 수행할 때 레이어 시스템으로 구성되므로 빈번히 변경되는 파일일수록 제일 마지막에 작성하는게 좋다.
COPY <파일> <경로>

  • package.json 파일을 현재 경로에 복사
    COPY package.json ./

파일 중 소스코드를 담고 있는 index.js 가 디펜던시에 대한 정보를 담고 있는 package.json 이나 package-lock.json 보다 빈번히 변경되므로 제일 나중에 복사한다.

RUN

RUN 은 실행 명령어 입니다.
RUN <커맨드>

npm install 을 사용하면 최신 버전이 설치되어 버전이 달라질 수 있기 때문에 개발 시 사용한 정확한 버전을 설치하도록 package-lock.json 을 참고하는 npm ci 를 사용하는 것이 좋다.

  • npm 패키지 설치
    RUN npm install <패키지>

ENTRYPOINT

ENTRYPOINT 명령어는 이미지가 컨테이너로 만들어져 실행될 때 항상 실행되어야 하는 커맨드를 지정합니다.
ENTRYPOINT <커맨드>

  • npm start
    ENTRYPOINT npm start

중요💡

Dockerfile 은 layer 형태로 작성하는 것이 좋다.
제일 빈번히 변경되는 것일수록 제일 마지막에 작성하여 레이어 제일 위쪽에 위치하게 한다.
그러면 이후 소스파일이 변경되어 새로운 image 를 만들어야 할 때, 변경된 레이어만 변경하고 나머지는 재사용 할 수 있어 image 를 빌드하는데 더 효율적이다.

완성된 Dockerfile

FROM node:16-alpine

WORKDIR /app

COPY package.json package-lock.json ./

RUN npm ci

COPY index.js .

ENTRYPOINT ["node", "index.js"]

4. Image 만들기 🖼

Docker CLI

build

docker build -f Dockerfile -t my-first-docker .

  • .
    build context 최상위 경로에 Dockerfile 이 있다.
  • -f, --file
    Dockerfile 을 가리킨다.
    기본적으로 Dockerfile 이라고 작성하지만 다른 이름을 지정할 수 있다.
    default = 'PATH/Dockerfile'
  • -t, --tag
    -tag
    Docker image 의 이름을 지정한다.


Dockerfile 에 작성한대로 순차적으로 실행되는 것을 볼 수 있다.

images

docker images 명령어를 사용하면 생성된 image 파일을 볼 수 있다.

  • REPOSITORY
    github의 repository 와 동일하며, container 에 올릴 때 이 이름을 재사용하게 된다.

  • TAG
    image 버전을 따로 지정하지 않았기 때문에 default 값인 lastest 이다.

run

docker run -d -p 8080:8080 my-first-docker

  • -d, --detach
    container 가 백그라운드에서 실행되고 있게 한다.
    node.js 백엔드 어플리케이션이기 때문에 terminal 이 기다리지 않도록 detach 해준다.

  • -p, --publish
    <host 의 포트>:<container 의 포트>
    constainer 는 고립된 환경에서 동작하므로 host 의 포트와 container 의 포트를 연결한다.

5. 실행 결과 🐳

docker ps 명령어로 실행중인 container 의 리스트를 확인할 수 있다.

localhost:8080 으로 들어가보면...

추가 명령어

  • docker logs <container id>

    container 에서 발생하고 있는 터미널 메세지 (로그) 를 확인할 수 있다.

  • docker tag
    image 파일의 이름을 변경한다.

배포 (Docker hub)

Repository 생성 📁

Docker hub에서 새로운 repository 를 만들면, Docker commands 에 어떻게 image 를 push 할 수 있는지 알려준다.

docker push <docker 계정>/<repository 이름>:<태그>

image 이름 변경 ✏️

tag 명령어를 사용하여 만들었던 image 의 이름을 docker 계정을 넣어 새롭게 만들어 준다.

로그인 🔑

docker login 명령어를 사용하여 로그인한다.

push 📤

docker push moonshadow95/my-first-docker:latest

push 완료!

profile
🌑🌘🌗🌖🌕

0개의 댓글