개요

우리 모두 한 번쯤은 그런 경험이 있다. 프로그램을 설치하면서 분명 하라는대로 한 것 같은데 계속 오류가 나서 인터넷을 찾아봤을 때 해결 방법은 나오지만 도저히 따라할 엄두가 나지 않을 때.

만약 누구나 같은 환경에서 프로그램을 설치하고 사용할 수 있다면 어떨까? 프로그램을 만드는 입장에서 동작하는 환경 그대로 사용자에게 제공하기만 하면 되는 것이다.
이 것이 바로 가상화 기술이다.

실생활에서의 예로 대학교 시절 학교 기관에서 미세조류를 생산하고 판매하는 사업을 했었다. 미세조류를 생산할 수 있는 환경을 컨테이너 안에 넣고 통째로 수출했었는데 이는 환경에 따라 생산량이 달라지거나 실패할 수도 있기 때문에 하나의 격리된 컨테이너에서 환경을 셋팅한 뒤 그대로 수출했던 것이다.

만약 똑같은 일을 하는 서버가 여러대 있다고 해보면 이 둘은 운영체제, 컴파일러, 하드웨어 등등 여러가지 차이점이 있고 이러한 차이가 문제로 이어질 수 있다.

가상화 기술을 사용하면 서버마다 동일한 환경을 구성해주기 때문에 제공하는 컴퓨터에서 동작하면 다른 컴퓨터에서도 똑같이 동작한다.

그리고 동일한 환경을 구성하기 때문에 서버를 증설할 일이 있을 때 auto scailing에 유리하다.

일단 가상화 기술이란 실제론 없는데 있는 것처럼 보이게 하는 것을 말하며 C드라이브 D드라이브처럼 하나의 하드디스크를 나누는 것과 같다. 실제론 하나의 하드 디스크만 있을 뿐인데 말이다.

가상화 기술을 이용하여 여러 개의 운영체제도 쓸 수 있다. 윈도우에서 리눅스를 쓸 수 있고 윈도우 안에서 윈도우도 쓸 수 있게 된다. 그러나 가상 머신 자체는 완전한 컴퓨터라 이런 경우 여러 개의 다른 운영체제를 동시에 돌리기에 속도 저하가 일어나게 되고 이미지 파일에 운영체제 파일이 있기 때문에 무겁다는 문제가 있었다.

이러한 문제를 해결하고자 등장한 것이 바로 컨테이너 기반 가상화 기술이고 대표적인 것이 바로 도커이다.

도커는 로고와 이름으로 그 기능을 알 수 있는데 도커는 사전적 의미로 컨테이너를 하역하는 항만 노동자를 뜻한다. 그림에서도 고래가 컨테이너 박스 여러 개를 싣고있다. 이는 서버가 여러개의 컨테이너를 적재한다는 것으로 이해할 수 있다. 컨테이너에 물건을 싣는 것처럼 서비스 운영에 필요한 요소들을 모아 도커 컨테이너에 넣는다.

도커는 각각의 OS를 돌리지 않고 도커를 설치하고 리눅스라는 하나의 OS위에 컨테이너를 올려 어떤 조건에서도 동일한 환경에서 작업을 할 수 있게 해준다.

도커 이미지

도커는 이미지를 사용하는데 이 이미지라는 것은 특정 프로세스를 실행시키는데 필요한 여러 파일들과 설정값들을 모아놓은 것이다.

도커 파일

도커 파일이란 도커 이미지를 구성하기 위해 있어야할 패키지, 의존성, 소스코드 등을 하나의 파일로 기록하여 이미지화 시킬 명령 파일이다.

만약 프로젝트를 도커 이미지로 만들어서 배포한다면 도커 파일을 작성해야한다.

도커 파일의 주요 명령어는 다음과 같다.

  • FROM : 이미지를 생성할 때 기반으로 사용할 이미지 지정
  • ARG : 이미지 빌드시 사용할 변수 지정
  • COPY : 호스트에 있는 파일이나 디렉토리를 도커 이미지의 파일 시스템으로 복사
  • ENV : 컨테이너에서 사용할 변수 지정
  • ENTRYPOINT : 컨테이너가 실행되었을 때 항상 실행되어야하는 커멘드 지정

예를 들어 스프링부트 프로젝트를 도커 이미지화 시키기 위해 작성해야하는 도커 파일은 다음과 같다.

FROM openjdk:17
ARG JAR_FILE=build/libs/app.jar
COPY ${JAR_FILE} ./app.jar
COPY sample.csv ./
ENV TZ=Asia/Seoul
ENTRYPOINT ["java", "-jar", "./app.jar"]

도커 컴포즈

만약 여러개의 컨테이너를 연결하여 하나의 애플리케이션을 구성해야한다면 어떻게 해야할까?
스프링 서버 + 레디스, 스프링 서버 + 데이터베이스
이럴 때 도커 컴포즈를 사용할 수 있다.

도커 컴포즈란 멀티 컨테이너 도커 애플리케이션을 정의하고 실행하는 도구로 서비스 구축, 네트워크 연결, 실행 순서를 자동으로 관리해준다.

이는 docker-compose.yml파일을 작성하고 실행하는 것 만으로도 사용이 가능하다.

간단하게 스프링 서버, DB, Redis를 컴포즈로 묶어보자

  1. 프로젝트를 빌드하여 jar파일을 생성한다.
  2. 각각의 도커 파일을 작성한다.

도커 컴포즈 파일은 다음과 같은 형식으로 작성하면 된다. version: services: servicename container_name build depends_on image environment volumes ports restart

version: "1.0"
services:
  simple_sns_redis:
    container_name: simple_sns_redis
    build:
      dockerfile: Dockerfile
      context: ./redis
    image: zxc5434/simple_sns_redis
    ports:
      - "6379:6379"
  simple_sns_database:
    container_name: simple_sns_database
    build:
      dockerfile: Dockerfile
      context: ./database
    image: zxc5543/simple_sns_database
    enviroment: 
      - MYSQL_DATABASE=simple_sns
      - MYSQL_ROOT_PASSWORD=${SPRING_DATASOURCE_PASSWORDS}
    volumes:
      - ./database/config:/etc/mysql/conf.d
    ports:
      - "3306:3306"

이런식으로 작성하고 아래의 명령어를 사용하여 동작시키고 중지시킨다.

docker-commpose -f docker-commpose.yml up
docker-commpose -f docker-commpose.yml down

만약 도커 컨테이너 내부에서 사용할 값이 있다면 이를 깃허브에 올리지 않고 도커 컴포즈 파일과 같은 경로에 .env확장자를 가진 파일을 작성하여 관리할 수 있다.

docker-compose config
docker-compose up
docker-compose up --build

첫 번째 명령어는 env파일을 자동으로 반영하도록 하는 명령어, 두 번째 명령어는 이미지가 없을 때 이미지 빌드 후 컨테이너를 실행하는 것, 세 번째 명령어는 이미지가 있든 없든 재빌드하여 컨테이너를 실행하는 명령어이다.