[내일배움캠프 Spring 심화] 2024.08.09 TIL

박상훈·2024년 8월 9일

[내일배움캠프] TIL

목록 보기
9/20

Docker와 Docker compose에 대해 학습하고 실습을 진행했다.


Docker

Docker 란?

  • Docker는 애플리케이션을 쉽게 만들고, 테스트하고, 배포할 수 있게 도와주는 소프트웨어 플랫폼이다.

  • 애플리케이션을 컨테이너라는 가볍고 이식성 있는 패키지로 실행할 수 있다.

  • Docker 이미지는 애플리케이션을 실행하는 데 필요한 모든것(코드, 런타임, 시스템 도구, 시스템 라이브러리 등)을 포함한다.

특징

  • 컨테이너화: 애플리케이션과 필요한 모든 것을 하나의 패키지로 묶어 어디서든 실행할 수 있다.

  • 경량: Docker는 운영 체제의 커널을 공유하므로, 가상 머신보다 훨씬 가볍고 빠르게 실행된다.

  • 이식성: Docker 컨테이너는 어디서든 동일하게 실행된다. 예를 들어, 개발자의 컴퓨터에서 테스트 서버, 운영 서버까지 동일하게 동작한다.

  • 확장성: Docker를 사용하면 여러 개의 컨테이너를 효율적으로 관리하고 쉽게 확장할 수 있다.

주요 키워드

  • 이미지 (Image)

    • 애플리케이션과 모든 실행에 필요한 파일(코드, 런타임, 라이브러리, 환경 변수, 구성 파일 등)을 포함한 읽기 전용 템플릿
    • 이미지는 컨테이너를 생성하기 위한 청사진 역할을 한다.
  • 컨테이너 (Container)

    • 이미지를 실행하여 동작하는 애플리케이션 인스턴스
    • 이미지가 정적인 템플릿이라면, 컨테이너는 실제로 애플리케이션이 실행되는 동적인 환경
    • 컨테이너는 격리된 공간에서 애플리케이션을 실행하며, 필요한 모든 의존성을 포함
    • 하나의 시스템에서 여러 개의 컨테이너를 독립적으로 실행할 수 있다.
  • Dockerfile

    • Dockerfile은 Docker 이미지를 생성하기 위한 스크립트이다. 이 파일에는 이미지를 빌드하는 데 필요한 명령어들이 포함되어있다.
    • Dockerfile을 사용하면 이미지 생성 과정을 자동화하고 일관되게 만들 수 있다.
  • Docker Hub

    • Docker Hub는 Docker 이미지를 공유하고 저장하는 중앙 저장소이다.
    • 사용자는 Docker Hub에서 다양한 공개 이미지를 다운로드하거나 자신만의 이미지를 업로드할 수 있다.
  • 볼륨 (Volume)

    • 볼륨은 컨테이너의 데이터를 지속적으로 저장할 수 있는 메커니즘이다.
    • 컨테이너가 삭제되더라도 볼륨에 저장된 데이터는 유지된다.
    • 볼륨을 사용하면 데이터를 컨테이너와 독립적으로 관리할 수 있다.
  • 네트워크 (Network)

    • Docker 네트워크는 컨테이너 간의 통신을 관리하는 방식이다.
    • Docker는 여러 가지 네트워크 드라이버를 제공하여 다양한 네트워크 설정을 지원한다.
    • 기본적으로 모든 컨테이너는 브리지 네트워크를 통해 통신할 수 있다.

Docker Compose

Docker Compose란?

  • 다중 컨테이너 Docker 애플리케이션을 정의하고 실행하기 위한 도구이다.
  • docker-compose.yml 파일 하나로 애플리케이션의 서비스, 네트워크, 볼륨 등을 정의할 수 있다.

Docker Compose 파일 구조

  • docker-compose.yml:
    • Docker Compose 파일은 YAML 형식으로 작성되며, 애플리케이션의 서비스, 네트워크, 볼륨 등을 정의한다.

    version: '3'
    services:
      web:
        image: nginx
        ports:
          - "8080:80"
      app:
        build: .
        ports:
          - "8081:8080"
        depends_on:
          - db
      db:
        image: postgres
        environment:
          POSTGRES_PASSWORD: example
  • version: Docker Compose 파일의 버전을 지정한다.
  • services: 애플리케이션의 각 서비스를 정의한다.
  • web, app, db: 각각의 서비스 이름이다.
  • image: 서비스를 실행할 Docker 이미지를 지정한다.
  • build: Dockerfile이 있는 디렉토리 경로를 지정하여 이미지를 빌드한다.
  • ports: 호스트와 컨테이너 간의 포트를 매핑한다.
  • depends_on: 다른 서비스가 먼저 실행되어야 하는 순서를 지정한다.
  • environment: 컨테이너의 환경 변수를 설정한다.

Docker Compose 명령어

docker compose up

  • docker-compose.yml 파일에 정의된 서비스를 빌드하고 시작한다. 만약 이미 빌드된 이미지가 있다면 이를 사용한다.
  • 백그라운드에서 실행하려면 d 옵션을 추가한다.
docker compose up -d
docker compose -f /path/to/your/project/docker-compose.yml up

docker compose down

  • 실행 중인 모든 서비스를 중지하고 컨테이너, 네트워크, 볼륨 등을 정리한다.
docker compose down

docker compose build

  • docker-compose.yml 파일에 정의된 서비스를 빌드한다.
docker compose build

docker compose ps

  • 현재 실행 중인 서비스를 확인한다.
docker compose ps

docker compose logs

  • 실행 중인 서비스의 로그를 확인한다.
docker compose logs

실습

  • 2개의 스프링 컨테이너를 생성하고 사용자가 service-a 컨테이너의 컨트롤러를 호출하면, service-b 컨테이너를 호출한다.
  • 최종 사용자에게 노출 되는 메시지는 아래와 같다.
    ”service-a: hi ###### service-b: hello”
  • 메시지 “service-b: hello” 는 service-b 컨테이너의 메시지이다.

프로젝트 생성

  • Spring initializr를 사용해 프로젝트를 두 개 생성한다.
  • 하나의 컨테이너가 서로 다른 컨테이너를 호출해야 하므로 아래와 같이 OpenFeign 디펜던시까지 포함하여 프로젝트를 생성한다.

service-a

  • AApplication.java
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    
    @EnableFeignClients
    @SpringBootApplication
    public class AApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(AApplication.class, args);
    	}
    
    }
  • AController.java
    import lombok.RequiredArgsConstructor;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequiredArgsConstructor
    public class AController {
    
        private final BServiceClient bServiceClient;
    
        @GetMapping("/hi")
        public String hello() {
            String hello = bServiceClient.getHello();
            return "sevice-a: hi ###### service-b: " + hello;
        }
    }
  • BServiceClient.java
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    
    @FeignClient(name = "service-b", url = "${service.b.url}")
    public interface BServiceClient {
        @GetMapping("/hello")
         public String getHello();
    }
  • application.properties
    spring.application.name=service-a
    
    server.port=18080
    
    service.b.url=http://localhost:18081

service-b

  • BController.java
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class BController {
    
        @GetMapping("/hello")
        public String hello() {
            return "hello";
        }
    }
  • application.properties
    spring.application.name=service-b
    
    server.port=18081

RUN

도커 컴포즈 사용

application.properties 수정

도커의 외부 포트를 조절하여 애플리케이션을 실행할것이기 때문에 포트를 모두 아래와 같이 8080으로 변경한다.

  • service-a > application.properties
    spring.application.name=service-a
    
    server.port=8080
    
    service.b.url=http://service-b:8080
  • service-b > application.properties
    spring.application.name=service-b
    
    server.port=8080

Docker compose 파일 생성

  • service-a 프로젝트와 service-b 프로젝트의 상위 폴더에서 docker-compose.yml 파일을 생성하여 아래와 같이 작성한다.
version: '3.8'

name: myProject

services:
  service-a:
    image: img-service-a
    ports:
      - "18080:8080"
    environment:
      - SERVICE_B_URL=http://service-b:8080
    depends_on:
      - service-b

  service-b:
    image: img-service-b
    ports:
      - "18081:8080"

networks:
  default:
    driver: bridge

나의 경우 에러가 발생하여 프로젝트명을 명시해두었다. 원래는 명시하지 않아도 된다. (작성하지 않아 발생한 관련 이슈 👉 클릭)

실행

  • 도커 컴포즈를 실행한다.
docker compose up -d
  • 두 개의 스프링 프로젝트가 컨테이너로 생성되어 동시에 돌아 간다.
profile
안녕하세요

0개의 댓글