6 분 소요

Docker


docker란 리눅스 컨테이너 기술을 기반으로, 애플리케이션의 환경을 빠르게 쉽게 구축할 수 있는 플랫폼이다.

용어

컨테이너


애플리케이션이 의존성, 네트워크 환경, 파일 시스템에 구애받지 않고, 도커라는 기술 위에 실행될 수 있도록 만든 애플리케이션 상자

이미지


실행되는 모든 컨테이너는 이미지로부터 생성되며, 이미지는 애플리케이션 및 애플리케이션 구성을 함께 담아 놓은 템플릿이다. 이미지를 이용하여 여러 개의 컨테이너를 생성할 수 있으며, 이는 수평확장에 용이하다. 또한 이미지는 기존의 이미지로부터 변경 사항을 추가/커밋하여 다른 이미지를 만들 수 있어 업데이트에 용이하다.

레지스트리

이미지는 레지스트리라는 공간에 저장되며, 대표적인 이미지 레지스트리로는 Docker Hub, Amazon ECR이 있다. 도커 CLI에서 이미지를 이용해 컨테이너를 생성할 때, 호스트 컴퓨터에 이미지가 존재하지 않는다면, 기본 레지스트리로부터 다운로드한다.

Docker 컨테이너 방식의 장점

의존성 충돌 문제 해결(리소스 격리성)


어플리케이션은 해당 어플리케이션을 실행하기 위해 어떤 환경이 구축되어야 있어야 하는데, 동일한 컴퓨터에 서로 다른 프로그램의 각각의 요구하고 있는 버전이 다르다면, 둘 중 한 어플리케이션은 제대로 된 실행을 보장할 수 없다.(의존성 충돌) 그러나 Docker 방식의 컨테이너의 경우, 어떠한 의존성도 공유하지 않고, 각자 고유의 의존성을 포함하고 있기 때문에 의존성 충돌 문제 해결이 가능하다.

컨테이너 격리

  1. 프로세스
    • 특정 컨테이너에서 작동하는 프로세스는 기본적으로 그 컨테이너 안에서만 엑세스할 수 있다.
    • 컨테이너 안에서 실행되는 프로세스는 다른 컨테이너의 프로세스에게 영향을 줄 수 없다.
  2. 네트워크
    • 기본으로 컨테이너 하나에 하나의 IP 주소가 할당되어 있다.
  3. 파일 시스템
    • 컨테이너 안에서 사용되는 파일 시스템은 구획화 되어 있어, 컨테이너에서의 명령이나 파일 등의 엑세스를 제한할 수 있다.

개발과 배포 환경 일치(환경 표준화)


docker는 어플리케이션의 런타임 환경 및 시스템 환경 변수를 이미지로 추출하여 저장하고, 원한다면 해당 이미지를 컨테이너로 생성하여 해당 컨테이너에서 어플리케이션을 실행시킬 수 있기 때문에 도커를 통해 OS에 상관없이 즉시 애플리케이션 실행 환경을 만들 수 있으며, 개발을 컨테이너 위에서 진행할 경우, 모든 개발팀이 동일한 환경 하에 개발을 진행할 수 있다.

이는 배포시에도 Amazon Web Service의 EC2에 도커를 설치하거나, 도커 컨테이너를 EC2 서버에 실행할 수 있게 하는 서비스인 ECS를 사용한다면 보다 쉽게 애플리케이션을 배포할 수 있다.

수평 확장 용이 & 서버 업데이트 용이


만약 해당 서비스의 트래픽이 많아져 서버 증설이 요구될 때, 도커 컨테이너가 존재하지 않는다면, 기존 서비스와 동일한 서버를 구축하기 위해 기존 서버의 모든 실행 환경 구성을 셋팅해야 하지만, 도커 컨테이너를 활용하여 애플리케이션을 실행했다면, 해당 이미지를 바탕으로 새로운 서버에 해당 어플리케이션을 실행하고, 로드 벨런서에 서버를 추가해주기만 하면 된다. 이러한 기술을 활용하여 새로운 버전의 어플리케이션을 여러 서버 중 몇 대만 운영하여 테스트하는 방법도 가능하다.

Docker 사용하기

Docker 설치

img1

레지스트리에서 이미지 가져오기


이미지는 Registry_Account/Repository_Name:Tag 정보로 구성되어져 있으며 각 역할은 다음과 같다.

  • 레지스트리(Registry)
    • DockerHub, Amazon ECR 등과 같은 곳으로 도커 이미지를 관리하는 공간이다.
    • 따로 설정을 하지 않는다면, 도커 허브를 기본 레지스트리로 설정한다.
    • 레지스티리는 Docker Hub, Private Docker Hub, 회사 내부용 레지스트리 등으로 나뉠 수 있다.
  • 레포지토리(Repository)
    • 레지스트리 내에 도커 이미지가 저장되는 공간이다.
    • 이미지 이름이 사용되기도 한다.
    • Github Repository와 유사하다.
  • 태그(Tag)
    • 해당 이미지를 설명하는 버전 정보를 주로 입력한다.
    • 따로 설정하지 않는다면, latest 태그를 붙인 이미지를 가져온다.

이러한 정보로 구성된 이미지는 DockerHub로 접속하여 이미지를 확인한 후, Docker Pull Command를 통해 자신의 도커로 가져올 수 있으며, Overview를 통해 이미지에 대한 설명, Tag를 통해 버전 정보를 확인할 수 있다.

img3

자신의 도커에 있는 이미지는

docker image ls

명령어로 확인하거나 DockerApp - images을 통해 확인할 수 있다.

img4

가져온 이미지 컨테이너로 옮겨 실행하기


이미지를 레지스트리에서 가져왔다면, 이미지를 구동시킬 컨테이너에 넣은 후, 실행시킨다. 이는 간단하게 명령어로는

docker container run --name [컨테이너 이름] [이미지 이름]

과 같이 실행하면 되고, DockerApp으로는 해당하는 이미지의 Run을 눌러준 후, 설정하면 된다.

img5

이후 컨테이너는

docker container ps -a

명령어를 통해 확인하거나 DockerApp - Containers에서 확인 가능하며, 삭제는

docker container rm [컨테이너 이름]

이나 DockerApp의 Container Remove를 통해 삭제할 수 있다.

img6

Docker 컨테이너에 파일 복사하기


만약 이미지가 모두 구성되어 있지 않아 예를 들러 서버만 가져온 이미지를 사용하고 서버를 구성하는 파일을 올려야 할 경우, Docker 이미지와 로컬 파일을 연결하여 활용한다. 이는 서버에 문제가 생기는 것을 호스트와 별개로 파악할 수 있는 장점이 있으며, 문제가 생긴 서버를 끄고 도커 이미지로 서버를 재구동할 수 있는 장점이 있다.

로컬 파일과 도커 이미지를 연결하는 방법은 크게

  • CP(copy) : 호스트와 컨테이너 사이에 파일을 복사(Copy)
  • Volume : 호스트와 컨테이너 사이에 공간을 마운트(Mount)
    • 저장 공간을 다른 장치에서 접근할 수 있도록 경로를 허용해서, 마치 하나의 저장공간을 이용하는 것처럼 작업

로 나뉜다.

CP(Copy)

Copy의 경우 기존의 컨테이너의 경로에 파일을 복사하는 형태로 이루어지는데, 명령어는 다음과 같다.

docker container cp ./ [컨테이너 이름]:/usr/local/apache2/htdocs

이 때, ./ 는 현재 디렉토리를 의미하며, 파일을 담고 있는 폴더에 접근하여 해당 명령을 실행해야 한다.

그러면

img7

이와 같은 기본 웹 서버가

img8

해당 과정을 통해

img9

이와 같이 적용되는 것을 볼 수 있다.

Mount

Mount의 경우 로컬의 볼륨을 컨테이너가 공유하는 형태로 이루어지는데 , 순서는

  • 볼륨 생성 및 조회
  • 볼륨 마운트

로 이루어진다.

먼저 볼륨 생성은 DockerApp - Volume에서 Create를 하거나

docker volume create [볼륨 이름]

명령어를 통해 실행되며, 이는 DockerApp - Volume이나

docker volume ls

를 통해 확인 가능하며, 볼륨에 대한 자세한 정보를 알고 싶을 때는

docker volume inspect [볼륨 이름]

를 통해 확인 가능하다.

img14

img15

위와 같이 생성된 볼륨은 컨테이너에 마운트해야 공유 사용이 가능한데, 이는 컨테이너 실행과 함께

docker run -it -v [볼륨 이름]:[연결할 경로] --name [컨테이너 이름] [연결할 컨테이너 이름] 

명령어를 통해 마운트 된다. 마운트는 하나의 볼륨에 다수의 컨테이너 공유도 가능하며, 마운트시 로컬 파일이 마운트한 컨테이너에 공유되기 때문에 파일이 공유된다. 하지만 mac의 경우 vm위에 도커가 내장된 구조이기 때문에 /var/lib/docker가 없다. 따라서 mac은 볼륨을 따로 생성하지 않고, 로컬 디렉토리를 컨테이너로 마운트하는 형태로

docker run -it -v [로컬 경로]:[컨테이너의 연결할 경로] [이미지 이름] 
# 여기서 로컬 경로는 절대 경로로 작성해야 한다.

위 코드와 같이 작성하며,

img16

img17

img18

결과, 성공적으로 파일이 공유되며 삭제는

docker volume rm [볼륨 이름]

이나 DockerApp - Volume에서 삭제할 수 있다.

Docker Volume

-> 여기서 만약 제대로 적용되지 않는다면,

docker exec -it [컨테이너 이름] bash

명령어나 DockerApp에 Open In Terminal을 통해 컨테이너 내부 터미널로 이동하여 확인할 수 있다.

Docker 이미지 만들기


앞서 생성한 Docker Container를 이미지로 변환하는 작업은 작업 수행을 단축해주며 배포 및 관리가 유용하다.

이러한 작업은

  • 구동한 Docker Container를 이미지로 만드는 방법(Commit)
  • Docker Image 빌드를 위한 파일인 Dockerfile로 만드는 방법

으로 나뉜다.(Dockerfile)

구동한 Docker Container를 이미지로 만드는 방법

docker container commit [컨테이너 이름] [이미지 이름]:[tag]

로 Docker Container를 이미지로 생성 가능하다.

img10

Docker Image 빌드를 위한 파일인 Dockerfile로 만드는 방법

  • Dockerfile이란 이미지 파일의 설정 파일 느낌으로

img11

해당 이미지와 같이 생성된다. COPY 구문에 따라 경로를 설정해줘야 하며, FROM, COPY를 제외한 RUN, CMD, ENTRYPOINT등을 활용하여 이미지에 대한 설정을 해줄 수 있다.

Dockerfile Docs

  • 위와 같이 설정한 Dockerfile은
docker bulid --tag [이미지 이름] . 

을 통해 생성 가능하며, 실행시 지정된 경로의 Dockerfile을 찾아서 빌드한다.

img12

두 개이상의 Docker Container 연결하기


Docker에서는 docker-compose를 통해 docker-compose.yml(yaml)파일을 통해 container를 연결한다.

version: '3.8'

services:
  nginx:
    image: sebcontents/client
    restart: 'always'
    ports:
      - "8080:80"
    container_name: client

  node:
    image: sebcontents/server
    restart: 'always'
    ports:
      - "4999:80"
    container_name: server
    volumes:
      - "./volumefolder:/data"

  mysql:
    image: mysql:latest
    restart: 'always'
    ports:
      - "3307:3306"
    container_name: database
    environment:
      MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD}"
      MYSQL_DATABASE: "${MYSQL_DATABASE}"
      MYSQL_ROOT_USER: "${MYSQL_ROOT_USER}"
      MYSQL_ROOT_HOST: "${MYSQL_ROOT_HOST}"

위 코드와 같이 소스 이미지, 재시작 여부, 포트, 컨테이너 명, 환경 변수 등 여러가지를 설정할 수 있으며, docker-compose.yaml에 정의된 이미지를 컨테이너로 실행하는

docker-compose up 
# -d : 백그라운드 [이미지 이름] : 특정 이미지만 실행

명령어를 실행하면,

img13

위 이미지와 같이 container가 연결된 컨테이너를 볼 수 있다.

또한 컨테이너의 종료는

docker-compose down

으로 실행될 수 있다.

docker-compose docs

+ Container와 VM 비교

Container와 VM은 둘 다 프로세스, 네트워크, 파일 시스템을 격리할 수 있다는 장점을 공유하지만 작동원리는 다르다.

img19

위 그림과 같이 VM에는 OS가 존재하지만, Container는 OS가 존재하지 않는다. 이는 각 컨테이너는 호스트 OS 커널을 공유하고 있기 때문이다. 그러나 컨테이너에서 호스트와 다른 운영체제를 요구한다면 어떨까?

이는 volume에서 잠깐 언급했던, VM 형태로 실행(하이퍼바이저)으로 이루어진다. 또한 Docker Hub에 존재하는 각종 OS의 이미지의 경우, 컨테이너 내 애플리케이션 구성의 편의를 위해 존재하는 이미지이지, 커널 수준의 OS는 올라가지 않는다.

+ Node.js 웹 앱의 도커라이징(컨테이너화)

도커라이징은 애플리케이션을 도커 컨테이너에서 돌릴 수 있도록 이미지로 만드는 과정을 의미한다.

NodeJs 도커라이징

본 포스팅은 코드스테이츠 BEB 과정을 수강하며 작성한 글입니다.

Reference
https://docs.docker.com/engine/reference/commandline/docker/