기존에 riot API를 활용하여 league of legend 게임 데이터를 수집하는 프로젝트를 진행했었다.

https://github.com/hamwoojo/riot-api

 

GitHub - hamwoojo/riot-api: riot-api collect server

riot-api collect server. Contribute to hamwoojo/riot-api development by creating an account on GitHub.

github.com

해당 프로젝트에 아쉬운 부분이 있어 많은 리팩토링을 진행하였었는데 항상 다시 볼 때마다 개선점이 보인다.

그중에 한 문제를 개선해보려고 한다.

이번에 맥북을 구매하면서 내 로컬에 환경 세팅을 하려고 하니 DB에 관한 새로운 세팅을 하는 게 너무 번거로웠다.
해당 문제를 해결하기 위해서 데이터베이스 마이그레이션을 적용해보려고 한다.

데이터베이스 마이그레이션이란?

데이터베이스 마이그레이션이란 데이터베이스 스키마의 버전을 관리하고, 애플리케이션의 변경 사항을 추적하여 데이터베이스 스키마를 업데이트하는 작업을 의미한다.

 

물론 해당 프로젝트는 Spring Data JPA를 활용하여 진행한 프로젝트여서, hibernate의 ddl 생성 옵션

  jpa:
    hibernate:
      ddl-auto: create

을 사용하면 되지만 해당 옵션은 로컬에서 환경 구성할 때는 쓸 수 있지만 운영 서버에서는 데이터 손실의 위험이 있어 너무 위험하여 쓸 수 없다. 또한 추후에 어떤 테이블이 업데이트된다면 그 내용을 관리해야 할 필요도 있다.
해당 이슈들을 방지하기 위해서 데이터베이스 마이그레이션을 적용해보기로 하였다.

 

해당 프로젝트에 사용한 기술 스택 버전은 다음과 같다.

Spring Boot

  • Version 2.7.10

Maven

  • Version : 3.8.1

PostgreSQL

  • Version : 14.1

postgresql 환경 구성하기위해서 도커를 활용하기로 하였다.
postgresql 컨테이너 생성 및 실행을 위해서 docker-compose.yml 파일을 작성하였다.

version: "3.0"

services:
  db:
    image: postgres:14.1
    container_name: postgres
    ports:
      - "5432:5432"
    volumes:
      - ./db_data:/var/lib/postgresql/data
    restart: always
    environment:
      POSTGRES_USER: "root"
      POSTGRES_PASSWORD: "local"
      POSTGRES_DB: "riot"

docker compose up -d 명령어로 postgresql을 실행하였다.

 

Spring Boot에서는 flyway를 활용하면 데이터베이스 마이그레이션을 적용할 수 있다.

flyway를 적용해보자.

pom.xml에 dependency를 추가한다.

<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
    <version>9.21.1</version>
</dependency>

application.yml에 flyway를 사용한다는 내용을 추가한다.

spring:
  flyway:
    enabled: true

 

src/main/resources/db/migration 디렉터리에 V0__init.sql 파일을 작성한다. 테이블을 생성할 DDL을 써주면 된다.
너무 길어서 테이블 중 하나의 예시만 작성 첨부하겠다.

CREATE TABLE public.api_info (
                                 api_info_id bigserial NOT NULL,
                                 api_name varchar(255) NULL,
                                 api_host varchar(255) NULL,
                                 api_url varchar(255) NULL,
                                 content_type varchar(255) NULL,
                                 description varchar(255) NULL,
                                 http_method varchar(255) NULL,
                                 rate_limit int4 NULL,
                                 rate_limit_interval int4 NULL,
                                 api_scheme varchar(5) NULL,
                                 CONSTRAINT api_info_pkey PRIMARY KEY (api_info_id)
);

그리고 애플리케이션을 실행하였는데, 오류가 발생했다.

Description:

An attempt was made to call a method that does not exist. The attempt was made from the following location:

    org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration$FlywayConfiguration.configureProperties(FlywayAutoConfiguration.java:227)

The following method did not exist:

    'org.flywaydb.core.api.configuration.FluentConfiguration org.flywaydb.core.api.configuration.FluentConfiguration.oracleSqlplus(boolean)'

The calling method's class, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration$FlywayConfiguration, was loaded from the following location:

    jar:file:/Users/mac/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.7.10/spring-boot-autoconfigure-2.7.10.jar!/org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class

The called method's class, org.flywaydb.core.api.configuration.FluentConfiguration, is available from the following locations:

    jar:file:/Users/mac/.m2/repository/org/flywaydb/flyway-core/9.21.1/flyway-core-9.21.1.jar!/org/flywaydb/core/api/configuration/FluentConfiguration.class

The called method's class hierarchy was loaded from the following locations:

    org.flywaydb.core.api.configuration.FluentConfiguration: file:/Users/mac/.m2/repository/org/flywaydb/flyway-core/9.21.1/flyway-core-9.21.1.jar


Action:

Correct the classpath of your application so that it contains compatible versions of the classes org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration$FlywayConfiguration and org.flywaydb.core.api.configuration.FluentConfiguration

 

해당 에러를 찾다가 확인해 보니 무지성으로 flyway 최신 버전을 적용하려다가 스프링 부트의 버전과 호환이 안돼서 생긴 문제였다.

내 스프링 부트의 버전은 2.7.10인데 해당 버전은 8.5 버전의 flyway를 사용해야 한다.

해당 내용은 스프링 페이지에서 확인이 가능하다

https://spring.io/projects/spring-boot#learn

 

Spring Boot

 

spring.io

본인이 사용하는 버전의 Reference Doc을 보면 된다.

본인은 2.7 버전이라서 2.7.15 버전을 택했다.

클릭한 뒤 제일 아래에 있는 Dependency Versions를 선택한다.

찾기(ctrl + f)로 flyway를 찾는다.

8.5 버전을 써야 한다는 걸 알 수 있었다.

8.5 버전으로 pom.xml을 수정하자.

<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
    <version>8.5.13</version>
</dependency>

DDL이 제대로 됐는지 확인하기 위해서 validate 옵션을 추가하였다.

jpa:
  hibernate:
    ddl-auto: validate

실행해 보면 성공적으로 된 걸 알 수 있다.

db에서도 flyway_schema_history 테이블이 자동으로 생성되어 있는 걸 확인할 수 있는데 이름에서 알 수 있듯이 flyway 히스토리를 관리해 주는 테이블이다. 테이블 내용을 한 번 알아보자.

flyway_schema_history는 Flyway가 관리하는 테이블 중 하나로, 데이터베이스의 스키마 버전 및 마이그레이션 작업에 대한 기록을 저장하는 테이블입니다. 
Flyway는 이 테이블을 사용하여 데이터베이스의 상태를 추적하고, 이미 적용된 마이그레이션 스크립트를 기록하여 중복 실행을 방지합니다.

다음은 flyway_schema_history 테이블 칼럼에 대한 설명이다.
installed_rank: 마이그레이션 스크립트가 설치된 순서를 나타내는 숫자입니다. 낮은 숫자일수록 이전에 실행된 스크립트를 의미합니다.
version: 마이그레이션 스크립트의 버전을 나타냅니다. 버전은 마이그레이션 스크립트 파일 이름에 포함된 숫자 또는 타임스탬프입니다. 
description: 마이그레이션 스크립트의 설명을 나타냅니다. 마이그레이션 스크립트 파일 이름에서 파생될 수 있습니다.
type: 마이그레이션 스크립트의 유형을 나타냅니다. 주로 "SQL" 또는 "BASELINE"이 사용됩니다. SQL은 일반적인 마이그레이션 스크립트를 의미하고, BASELINE은 초기 베이스라인 마이그레이션을 의미합니다.
script: 실행된 마이그레이션 스크립트 파일의 이름을 나타냅니다.
checksum: 마이그레이션 스크립트의 체크섬 값입니다. 체크섬은 스크립트의 내용을 해시한 값으로, Flyway가 스크립트를 변경하지 않았는지 검증하는 용도로 사용됩니다.
installed_by: 마이그레이션 스크립트를 설치한 사용자를 나타냅니다.
installed_on: 마이그레이션 스크립트가 설치된 날짜와 시간을 나타냅니다.
execution_time: 마이그레이션 스크립트 실행에 소요된 시간을 나타냅니다.

flyway_schema_history 테이블을 통해 Flyway는 현재 데이터베이스의 상태와 적용된 마이그레이션 스크립트들에 대한 정보를 추적하며, 이를 통해 중복 실행을 방지하고 데이터베이스 스키마의 버전을 관리합니다.

 

다음은 기초 데이터를 추가로 insert 해보려고 한다.

flyway도 버전을 통하여 관리하는데 버전 관리는 프로젝트나 팀의 네이밍 룰을 따르면 된다.

본인은 다음 버전을 0.1로 작성할 것이다.

INSERT INTO public.api_info (api_name,api_host,api_url,content_type,description,http_method,rate_limit,rate_limit_interval,api_scheme)
VALUES
('getUserEntries','kr.api.riotgames.com','/lol/league-exp/v4/entries/RANKED_SOLO_5x5/GRANDMASTER/I','json','Retrieve a list of users in the Grandmaster tier.','get',100,120,'https')
,('getUserEntries','kr.api.riotgames.com','/lol/league-exp/v4/entries/RANKED_SOLO_5x5/PLATINUM/IV','json','Retrieve a list of users in the Platinum IV tier.','get',100,120,'https')
,('getUserEntries','kr.api.riotgames.com','/lol/league-exp/v4/entries/RANKED_SOLO_5x5/PLATINUM/III','json','Retrieve a list of users in the Platinum III tier.','get',100,120,'https')
,('getUserEntries','kr.api.riotgames.com','/lol/league-exp/v4/entries/RANKED_SOLO_5x5/PLATINUM/II','json','Retrieve a list of users in the Platinum II tier.','get',100,120,'https')
,('getUserEntries','kr.api.riotgames.com','/lol/league-exp/v4/entries/RANKED_SOLO_5x5/PLATINUM/I','json','Retrieve a list of users in the Platinum I tier.','get',100,120,'https')
,('getUserEntries','kr.api.riotgames.com','/lol/league-exp/v4/entries/RANKED_SOLO_5x5/DIAMOND/IV','json','Retrieve a list of users in the Diamond IV tier.','get',100,120,'https')
,('getUserEntries','kr.api.riotgames.com','/lol/league-exp/v4/entries/RANKED_SOLO_5x5/DIAMOND/III','json','Retrieve a list of users in the Diamond III tier.','get',100,120,'https')
,('getUserEntries','kr.api.riotgames.com','/lol/league-exp/v4/entries/RANKED_SOLO_5x5/DIAMOND/II','json','Retrieve a list of users in the Diamond II tier.','get',100,120,'https')
,('getUserEntries','kr.api.riotgames.com','/lol/league-exp/v4/entries/RANKED_SOLO_5x5/DIAMOND/I','json','Retrieve a list of users in the Diamond I tier.','get',100,120,'https')
,('getUserEntries','kr.api.riotgames.com','/lol/league-exp/v4/entries/RANKED_SOLO_5x5/MASTER/I','json','Retrieve a list of users in the Master tier.','get',100,120,'https')
,('getUserEntries','kr.api.riotgames.com','/lol/league-exp/v4/entries/RANKED_SOLO_5x5/CHALLENGER/I','json','Retrieve a list of users in the Challenger tier.','get',100,120,'https')
,('getMatchList','asia.api.riotgames.com','/lol/match/v5/matches/by-puuid/{puuid}/ids','json','Retrieve a list of matches by PUUID.','get',100,120,'https')
,('getMatchDetail','asia.api.riotgames.com','/lol/match/v5/matches/{matchId}','json','Retrieve detailed match information by match ID.','get',100,120,'https')
,('getItems','ddragon.leagueoflegends.com','/cdn/{version}/data/ko_KR/item.json','json','Retrieve item information by version.','get',100,120,'https')
,('getChampions','ddragon.leagueoflegends.com','/cdn/{version}/data/ko_KR/champion.json','json','Retrieve champion information by version.','get',100,120,'https')
,('getSpells','ddragon.leagueoflegends.com','/cdn/{version}/data/ko_KR/summoner.json','json','Retrieve summoner spell information by version.','get',100,120,'https')
,('getRunes','ddragon.leagueoflegends.com','/cdn/{version}/data/ko_KR/runesReforged.json','json','Retrieve rune information by version.','get',100,120,'https')
,('getUserInfoDetail','kr.api.riotgames.com','lol/summoner/v4/summoners/{encryptedSummonerId}','json','Retrieve user information details by summoner ID to fetch match information.','get',100,120,'https')
,('getVersions','ddragon.leagueoflegends.com','/api/versions.json','json','Retrieve version information.','get',100,120,'https');

INSERT INTO public.api_params (api_info_id,data_type,description,is_required,"name",api_key,api_value,date_param_required)
VALUES
(13,'Long','Start time',true,'startTime','startTime',NULL,true)
,(13,'Long','End time',true,'endTime','endTime',NULL,true)
,(13,'String','Game type',true,'type','type','ranked',false)
,(13,'int','Page',true,'start','start','0',false)
,(13,'int','Number of items to load per page',true,'count','count','100',false);

V0.1__insert_base_data.sql로 해당 내용을 작성하고 실행하였다.

flyway history 테이블 조회
실제 데이터 조회

잘 된 걸 볼 수 있다.
다음에는 kafka와 연동하는 걸 써보려고 한다.

'Side Project > Riot Project' 카테고리의 다른 글

Mac os에서 kafka clustering 구축하기  (0) 2023.08.13

해당 글은
Wanted 프리온보딩 챌린지 8월 "도커 이미지 제작부터  클라우드 배포까지"를 수강한 내용을 토대로 정리한 글입니다.

 

지난주에 우리는 Docker란 무엇인가?

Docker의 기본적인 개념과 아키텍처를 알고, Docker Client(CLI)의 명령어를 통하여 이미지를 만들어보고 컨테이너를 실행하는 테스트를 진행하였다.
지난 번에 Docker Hub에서 httpd를 가져와서 컨테이너로 실행했었다.

 

Docker 아키텍처를 다시 한 번 복기해보자.

도커 아키텍처

지난 시간에 클라이언트에서 docker pull 명령어를 사용하여 Registry(Docker Hub)에서 이미지를 가져오고, 가져온 이미지를 빌드하여 컨테이너화하였다.

 

이번에는 Docker Hub에 이미지를 등록하려면 어떻게 해야하는 지 알아보려고 한다.

먼저 이미지 태그를 설정해야는데, Docker Hub에 이미지를 등록하려면 다음과 같은 규칙을 준수해야한다.

[Docker Hub 사용자명]/이미지명:[태그명]

이미지 태그 설정은 다음과 같은 방법으로 가능하다.

이미지를 빌드하기 전이라면 다음 명령어를 사용하면 된다.

docker build -t hamwoojo/my-httpd

빌드 후에 이미지 태그를 설정하고 싶다면 다음 명령어를 사용하면 된다.

docker image tag hamwoojo/my-httpd

만약 Docker Hub에 가입하지 않았다면 회원가입을 먼저 진행해야 한다.

https://hub.docker.com/

 

Docker Hub Container Image Library | App Containerization

Deliver your business through Docker Hub Package and publish apps and plugins as containers in Docker Hub for easy download and deployment by millions of Docker users worldwide.

hub.docker.com

회원 가입을 했다면 CLI에서 Docker Hub로 로그인을 하면 된다.

docker login

로그아웃도 가능하다.

docker logout

Docker Hub에 이미지를 올려보자.

 

docker push hamwoojo/my-httpd:latest

Docker Hub Repository에 가면 이미지가 잘 올라가있는지 확인 가능하다.

 

도커 네트워크 드라이버(Docker Network Driver)

도커 네트워크 드라이버는 여러 드라이버가 존재하며, 핵심 네트워크 기능을 제공합니다.

다음 명령어를 쳐서 도커 네트워크 목록을 확인할 수 있다.

docker network ls

다음과 같이 네트워크 드라이버를 확인할 수 있다. 각각에 대해 알아보자.

네트워크 드라이버(Network Drivers)

  • bridge : 기본 네트워크 드라이버, 동일한 도커 호스트에서 컨테이너 간의 통신을 도와준다.
  • host : 호스트의 네트워크를 직접 사용한다.
  • overlay : 서로 다른 도커 호스트의 컨테이너 간 통신을 도와준다.
  • none : 컨테이너를 호스트 및 다른 컨테이너로부터 완전히 격리한다.

해당 명령어를 활용하여 네트워크의 상세 정보를 볼 수 있다.

docker network inspect [Network ID or NAME]

docker network inspect bridge 명령어를 쳐보았다.

json으로 데이터가 표시되는데 중간에 Containers를 보면 연결된 컨테이너들에 대한 정보를 확인할 수 있다.

이번 실습에서는 워드프레스(WordPress) 컨테이너를 생성하고, 해당 네트워크를 생성해보려고 한다.

워드프레스(WordPress)란?

웹 사이트 및 블로그를 만들고 관리하는 데에 사용되는 무료 오픈소스 콘텐츠 관리 시스템(CMS)이다.

워드프레스는 PHP 로 작성된 오픈 소스 콘텐츠 관리 시스템으로, 기본적으로 MySQL을 데이터베이스 관리 시스템으로 사용하며, 중요한 기능과 데이터를 MySQL에 의존하고있다. 

https://ko.wordpress.org/

 

Blog Tool, Publishing Platform, and CMS - WordPress.org 한국어

아름다운 웹사이트, 블로그, 또는 앱을 쉽게 만드는 데 사용할 수 있는 오픈 소스 소프트웨어

ko.wordpress.org

 

따라서 워드프레스를 사용하기 위해서는 MySQL과 워드프레스가 필요하다.

MySQL과 워드프레스를 이미지로 가져와 컨테이너를 생성하고 실행해보자.

먼저 네트워크를 생성한다.

docker network create wordpress_net

docker run 시 mysql이 없다면 해당 이미지를 pull 해온다.

--name 이름을 지정한다.

-v 내 호스트 볼륨과 마운트할 컨테이 볼륨을 지정한다.
-e 는 환경 설정(environment)을 의미한다

--network 네트워크를 생성한 네트워크로 지정한다.

docker \
run \
    --name "db" \
    -v "$(pwd)/db_data:/var/lib/mysql" \
    -e "MYSQL_ROOT_PASSWORD=root_pass" \
    -e "MYSQL_DATABASE=wordpress" \
    -e "MYSQL_USER=docker_pro" \
    -e "MYSQL_PASSWORD=docker_pro_pass" \
    --network wordpress_net \
mysql:latest

-p 옵션으로 포트포워딩을 한다.

docker \
    run \
    --name app \
    -v "$(pwd)/app_data:/var/www/html" \
    -e "WORDPRESS_DB_HOST=db" \
    -e "WORDPRESS_DB_NAME=wordpress" \
    -e "WORDPRESS_DB_USER=docker_pro" \
    -e "WORDPRESS_DB_PASSWORD=docker_pro_pass" \
    -e "WORDPRESS_DEBUG=1" \
    -p 8000:80 \
    --network wordpress_net \
wordpress:latest

http://localhost:8000에 접속해보자.

다음과 같이 화면이 나오면 제대로 실행되고 있는 것이다.

만약 이렇게 하나 하나씩 docker run을 해야한다면 매우 귀찮을 것이다.
지금은 두 개를 실행해서 괜찮지만 마이크로서비스로 이루어져있다고 가정해보자.

50개의 모듈이 있다고 가정해보면, 하나씩 실행하면서 관리하려면 관리하기도 힘들고, 관리비용도 상승할 것이다.

 

이러한 단점을 docker compose를 활용하면 어느정도 해결할 수 있다.

 

도커 컴포즈(docker compose)란?

  • 도커 컨테이너를 일괄적으로 정의하고 제어하는 도구
  • 설정 파일을 도커 CLI로 번역하는 역할

도커 컴포즈를 사용하면 여러개의 컨테이너를 하나의 서비스로 정의해 컨테이너 묶음으로 제어할 수 있다.

도커 컴포즈는 yaml(YAML Ain't Markup Language) 형식으로 정의 파일을 작성한다.

정의 파일은 docker-compose.yml이라는 이름을 사용해야 하며, 이름을 다른 걸로 사용하려면 -f 명령어를 사용하여

파일명을 지정해야한다.

위에서 docker run을 두 번 실행해서 워드프레스를 실행했는데,

도커 컴포즈를 사용하면 하나의 파일, 하나의 명령어로 해결 가능하다.

다음은 위에서 실습한 워드프레스를 도커 컴포즈 정의 파일(docker-compose.yml)을 작성한 것이다.

하나씩 알아보자.

version: "3.0"

services:
  db:
    image: mysql:latest
    volumes:
      - ./db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root_pass
      MYSQL_DATABASE: wordpress
      MYSQL_USER: docker_pro
      MYSQL_PASSWORD: docker_pro_pass
  
  app:
    depends_on: 
      - db
    image: wordpress:latest
    volumes:
      - ./app_data:/var/www/html
    ports:
      - "8000:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: docker_pro
      WORDPRESS_DB_PASSWORD: docker_pro_pass 
  • version : 도커 컴포즈의 버전
  • services : 컨테이너의 집합
  • image : 사용할 이미지
  • volumes : 마운트(볼륨)을 설정
  • restart : 컨테이너 종료 시 재시작 여부
    - no : 재시작하지 않음
    - always : 항상 재시작
    - on-failure : 프로세스가 0 외의 상태로 종료됐다면 재시작
    - unless-stopped : 종료 시 재시작하지 않음, 그 외에는 재시작
  • environment : 환경 설정
  • depends on : 서비스 간의 종속성 정의
    - 컨테이너들 간의 실행 순서를 정의할 수 있다.
    - 워드프레스는 MySQL에 의존적이므로 MySQL없이 사용할 수 없다. 따라서 MySQL을 먼저 실행해야한다.
  • ports : 포트포워딩 설정

도커 컴포즈를 실행해보자.

docker-compose -f docker-compose.yml up --build

실행 결과

http://localhost:8000/

에 접속해보면 워드프레스가 잘 실행되는 걸 확인할 수 있다.

-d 옵션을 주면 백그라운드에서 실행가능하다.

중지를 하기 위해서는 두 개의 명령어가 실행이 가능하다.

 

두 명령어 다 현재 실행중인 컨테이너를 중지하는데 사용한다.

차이점은 stop 명령어는 중지된 컨테이너가 컴포즈 환경과 관련된 네트워크, 볼륨등과 함께 그대로 존재한다.

docker compose stop

반면에 down 명령어는 컨테이너를 중지하고, 관련된 모든 리소스를 제거한다.

down 명령어는 컴포즈 파일에 정의한 서비스 들과 함께 네트워크, 볼륨, 컨테이너들을 모두 제거한다.

관련된 모든 데이터가 삭제된다고 볼 수 있다.

docker compose down

 

'Study > On-boarding' 카테고리의 다른 글

Wanted 프리온보딩 챌린지 백엔드 도커 - 1  (0) 2023.08.02

해당 포스팅은
Wanted 프리온보딩 챌린지 8월 "도커 이미지 제작부터  클라우드 배포까지"를 수강한 내용을 토대로 정리한 글입니다.

 

 

공식 문서에서 도커를 알아보자

  • 애플리케이션 개발, 배포, 실행을 위한 Open Platform
  • 애플리케이션을 인프라에서 분리하여 신속한 소프트웨어 제공
  • 인프라를 애플리케이션을 관리하는 것처럼 관리할 수 있다.
  • 코드 배포 및 테스트에 용의하다.

https://docs.docker.com/get-started/overview/

 

Docker overview

 

docs.docker.com

Docker란 무엇일까?

  • 컨테이너 기반 가상화 도구(리눅스 컨테이너 기술인 Linux Containers 기반)
  • 애플리케이션을 컨테이너 단위로 격리하여 실행하고 배포하는 기술
  • 다양한 운영체제에서 사용할 수 있으며,
    컨테이너화 된 애플리케이션을 손쉽게 빌드, 배포, 관리할 수 있는 다양한 기능 제공
  • 위 기능들을 통해 애플리케이션을 빠르게 개발하고, 효율적으로 배포, 관리할 수 있음

여기서 의문이 하나 생긴다. 컨테이너란 대체 무엇일까?

한 번 찾아보자.

컨테이너(Container)란?

  • 컨테이너는 가상화 기술 중 하나
  • 호스트 운영체제 위에 여러 개의 격리된 환경을 생성
  • 각각의 컨테이너 안에서 애플리케이션을 실행

다시 꼬리 물기로 의문이 생긴다. 가상화 기술이란 무엇일까?

 

가상화(Virtualization) 기술이란?

하나의 물리적인 컴퓨터 자원(CPU, 메모리, 저장장치 등)을 가상적으로 분할하여
여러 개의 가상 컴퓨터 환경을 만들어 내는 기술이다.
이를 통해 물리적인 컴퓨터 자원을 더욱 효율적으로 사용할 수 있으며,
서버나 애플리케이션 등을 운영하는 데 있어 유연성과 안정성을 제공한다.

즉, 하나의 서버나 컴퓨터를 다양한 용도에 따라 가상 분할하여 사용하는 것이다.

VM


위 사진의 VM 구조를 보면 하이퍼바이저(HyperVisor)라는 게 있다.
하이퍼바이저란 가상 머신을 생성하고 구동하는 소프트웨어이다.

하이퍼바이저는 가상 머신 모니터(Virtual Machine Monitor, VMM)라고도 불리며, 하이퍼바이저는
하이퍼바이저 운영 체제와 가상 머신의 리소스를 분리해 VM의 생성과 관리를 지원합니다.

하이퍼바이저로 사용되는 물리 하드웨어를 호스트라고 하며, 리소스를 사용하는 여러 VM을 게스트라고 한다.
OS들의 요청을 번역하여 하드웨어에 전달하며, OS에 자원을 할당 및 조율한다.

 

여기서 다시 의문이 생긴다. 
VM과 Container 둘 다 가상 환경을 만들어서 사용하는 기술 아닌가?

둘의 차이점은 뭘까?

 

  • 가상화 수준: VM은 하이퍼바이저를 사용하여 물리적인 하드웨어 위에 여러 개의 독립적인 가상 머신을 생성한다.
    각 가상 머신은 호스트 운영체제와 완전히 격리되어 독립적인 운영체제와 커널을 실행한다.
    반면에 컨테이너는 호스트 운영 체제의 커널을 공유하여 각 컨테이너는 독립적인 파일 시스템과 프로세스 공간을 갖는다. 이로 인해 컨테이너는 VM보다 더 가볍고 빠르며 효율적으로 리소스를 활용한다.
  • 시작 속도 : VM은 가상 머신마다 별도의 운영체제를 실행해야 하기 때문에 시작 속도가 상대적으로 느릴 수 있다. 반면에 컨테이너는 호스트 운영 체제의 커널을 공유하고, 이미지를 레이어로 캐싱하므로 빠르게 시작할 수 있다.
  • 이식성 : 컨테이너는 환경에 독립적으로 동작하므로 개발한 애플리케이션을 동일한 환경에서 쉽고 빠르게 실행할 수 있다. 또한 클라우드나 다른 환경으로도 쉽게 이동이 가능하다. VM의 경우, 가상 머신 이미지를 다른 환경으로 이동하기 위해서는 추가적인 설정이 필요하다.
  • 성격 : VM은 보다 격리된 환경을 제공하므로 다양한 운영 체제와 응용 프로그램을 호스팅 하고, 다양한 운영 체제를 동시에 실행하는데 적합하다. 반면에 컨테이너는 하나의 운영 체제에서 여러 개의 서비스와 마이크로서비스를 실행하는 데 더 적합하다.

VM은 강력한 격리와 호환성이 필요한 경우에 적합하며, 컨테이너는 빠른 개발과 배포가 필요한 마이크로서비스에 더 적합하다고 볼 수 있다.

 

도커에 관한 이론을 알아보았으니, 도커의 구조에 대해서 알아보자.
다음은 공식 홈페이지의 도커 아키텍처이다.

도커 아키텍처

도커는 클라이언트-서버 아키텍처를 사용한다.

클라이언트는 Docker Daemon과 통신하여 컨테이너를 빌드, 실행, 배포한다. 

 

도커 데몬(Docker Daemon)

  • 도커 엔진의 핵심 구성 요소
  • 도커 호스트에서 컨테이너를 관리하고 실행하는 역할
  • 컨테이너를 생성, 시작, 중지, 삭제하는 등의 작업을 수행
  • 컨테이너 이미지를 관리
  • 외부에서 이미지를 다운로드하고 빌드하는 작업을 수행

도커 클라이언트(Docker Client)

  • 도커 데몬과 상호작용하기 위한 인터페이스
  • 커맨드라인 인터페이스(CLI) 제공
  • docker 명령어를 사용하면 Docker Daemon으로 보내어 실행

도커 오브젝트(Docker Object)

  • 도커 이미지(Docker Image)
    - 도커 컨테이너를 만들기 위한 읽기 전용 템플릿
  • 도커 컨테이너(Docker Container)
    - 한 도커 이미지의 실행 가능한 인스턴스
    - 애플리케이션을 실행하기 위한 모든 파일과 설정 정보를 포함하는 패키지

도커 레지스트리(Docker Registries)

  • 도커 이미지를 관리하고 저장하는 곳
  • Docker Hub : 디폴트 레지스트리, 누구나 접근 가능한 공개 저장소이다.

Docker Hub에서 docker pull로 원하는 이미지를 가져와 docker run 명령어를 통하여 컨테이너화 하고 실행할 수 있다.

 

그럼 Docker 명령어를 알아보자.

먼저 Docker Hub에서 httpd를 받아와 보자.

docker pull httpd

명령어를 통하여 잘 받았는지 확인해 보자.

docker images

docker images는 내 이미지 리스트를 불러온다.

 

 docker run

docker run은 주로 -p, -it, -d, -v옵션을 자주 사용한다.
-p 옵션은 도커 컨테이너와 호스트 간의 포트포워딩을 하는 옵션이다. 

예를 들면 다음 명령어는 호스트의 8888 포트를 컨테이너 내부 80 포트로 포워딩되어 호스트의 8888 포트로 Apache Web을 접근하는 예시이다.

 docker run -p 8888:80 httpd

-it는 컨테이너가 터미널과 인터랙티브 하게 동작하며, 터미널로 컨테이너에 입력하고 출력 결과를 확인할 수 있습니다.
주로 명령어 실행, 디버깅, 로그 확인 등에서 유용하게 사용할 수 있다.

-d 옵션은 백그라운드에서 실행하는 옵션이다.

 

-v 옵션은 -v <호스트 경로>:<컨테이너 경로> 형태로 사용하며 컨테이너와 호스트 간의 디렉터리 또는 파일을 마운트하는 옵션이다.

docker run -p 8888:80 -v 프로젝트 경로:/usr/local/apache2/htdocs httpd

docker run은 이미지로부터 새로운 컨테이너를 생성하고 실행까지 한다.

 

docker ps는 도커의 현재 실행 중인 컨테이너 목록을 확인할 수 있다.

-a 옵션을 주면 중지된 컨테이너를 포함한 모든 컨테이너를 조회할 수 있다.

 

docker ps

docker 도커 컨테이너를 중지한다.
컨테이너 ID로 중지가 가능한데 ID는 docker ps 명령어에서 찾을 수 있다.

 docker stop CONTAINER_ID

docker logs는 컨테이너의 로그를 확인하는 명령어이다.

docker logs CONTAINER_ID_또는_CONTAINER_NAME

docker rm 은 컨테이너를 삭제하는 명령어이다.
컨테이너가 실행 중이라면 삭제되지 않는다.

docker rm CONTAINER_ID

docker rmi는 이미지를 삭제하는 명령어이다.

마찬가지로 컨테이너에서 해당 이미지로 실행 중인 경우  이미지를 삭제할 수 없다.

docker rmi IMAGE_ID

docker exec 명령어는 지정된 컨테이너 내에서 셸을 실행하여 사용자가 컨테이너 내부에서 명령을 실행하고 상호 작용 할 수 있게 한다.

docker exec -it CONTAINER_ID /bin/sh

DockerFile 실습

이미지는 가져오는 것만 뿐만 아니라 직접 만들어서 컨테이너화 하여 실행할 수 있다.

먼저 Dockerfile을 작성한다.

FROM httpd:latest
COPY  index.html /usr/local/apache2/htdocs/index.html
EXPOSE 80

해당 Dockerfile은 Apache HTTP Server(httpd)를 사용하여 웹 서버를 실행하기 위한 설정이다.

httpd:latest는 Docker Hub의  httpd이미지 중 최신 버전을 사용하겠다는 의미이다.

Copy는 호스트에 있는 index.html 파일을 Docker image로 복사하겠다는 의미이다. 도커 이미지 내의 경로는 /usr/local/apache2/htdocs/index.html로 하겠다는 의미이다. 이 경로는 Apache HTTP Server에서 웹 콘텐츠를 제공하는 기본 디렉터리이다.

Expose 80은 Docker Container가 80 포트를 노출시킨다는 것을 명시하는 것이다.

index.html의 내용은 다음과 같이 구성되어 있다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>원티드 온보딩 챌린지 - 백엔드</title>
</head>
<body> 도커 실습 </body>
</html>

해당 명령어는 이미지를 my-httpd라는 태그를 가진 Docker 이미지를 빌드하는 명령어이다.

-t는 태그를 의미하며, '.'은 dockerfile을 빌드하기 위한 경로를 의미하며, 현재 디렉터리를 의미한다.
즉 Dockerfile이 있는 경로에 들어가서 해당 명령어를 사용해야 한다는 의미이다.

 docker build -t my-httpd .

 

docker images 명령어를 통하여 확인해 보면 다음과 같이 새로운 이미지가 생긴 걸 확인할 수 있다.

docker run IMAGE_ID를 통해 실행한다.

'Study > On-boarding' 카테고리의 다른 글

Wanted 프리온보딩 챌린지 백엔드 도커 - 2  (0) 2023.08.04

+ Recent posts