CI CD/Docker

[KEUPANG] Docker 를 활용하여 MSA 프로젝트 실행하기

playdodo 2024. 11. 27. 21:02
이전 페이지: api gateway 생성
다음 페이지: swagger 설정

1. 개요

MSA와 Docker의 필요성

  • 환경 일관성
    • 이후에 Naver Cloud Platform이나 AWS에 배포할 예정
    • 이때 다른 환경이라서 생길 수 있는 문제를 방지하기 위해 사용
  • 로컬에서 MSA 환경 구축
    • Docker Compose를 사용하면 로컬에서 Config Server, Eureka Server, API Gateway, 각 서비스를 포함한 MSA 전체를 한 번에 실행할 수 있다.
  • CI/CD 통합 용이
    • Docker를 사용하면 Jenkins, GitHub Actions 같은 CI/CD 파이프라인에 쉽게 통합됨.

결론은 이후에 진행해보고 싶은 배포 자동화를 편하게 하고, 일일이 서비스를 실행시키는 것이 귀찮아서 Docker를 미리 도입하게 됨.

2. 환경 설정

Docker 설치 및 설정

  • Docker 설치
    • 링크에서 Docker Desktop 설치
    • 터미널에서 버전 확인
      • Docker와 Docker Compose 버전이 정상 출력되면 설치 성공.
#docker version 확인
docker --version
#출력 결과 예시
Docker version 27.3.1, build ce12230

프로젝트 구조 설명

프로젝트 구조

  • 프로젝트 구조는 위와 같음

docker-compose.yml 파일 설명

모든 네트워크와 서비스는 이 파일로 정의하고 관리한다.

아래에 상세한 설명

3. Docker Compose 파일 구성

서비스별 Dockerfile 작성

각 서비스마다 Dockerfile을 작성해서 컨테이너화 한다.

적용한 Dockerfile 예시

# 1. Base image
FROM openjdk:17-jdk-slim

# 2. Work directory
WORKDIR /app

# 3. Copy JAR file
COPY build/libs/*.jar app.jar

# 4. Expose port
EXPOSE 8081

# 5. Run application
ENTRYPOINT ["java", "-jar", "app.jar"]

기본 이미지: OpenJDK 17 Slim 사용

애플리케이션 복사: 빌드된 JAR 파일을 컨테이너에 복사.

실행 명령: JAR 파일을 실행하는 명령어 설정

docker-compose.yml 파일 작성 및 설명

  • 모든 서비스를 docker-compose.yml로 관리
  • 주요 서비스는 Config Server, Eureka Server, Api gateway, User Service, Product Service
  • docker-compose.yml은 주요 서비스들을 담고 있는 root 폴더인 keupang에 넣으면 된다. (.env 파일도 같은 폴더 안에 있어야 한다!)
  • docker-compose.yml 예시
services:
    config-server:
        build:
            context: ./keupang-config-server
        ports:
            - "9000:9000"
        environment:
            - SPRING_PROFILES_ACTIVE=prod
            - private_key=${private_key}
        networks:
            - msa-network

    api-gateway:
        build:
            context: ./keupang-gateway
        ports:
            - "8080:8080"
        depends_on:
            - eureka-server
        environment:
            - security_username=${security_username}
            - security_password=${security_password}
        networks:
            - msa-network

    service-user:
        build:
            context: ./keupang-user
        ports:
            - "8081:8081"
        depends_on:
            - eureka-server
            - config-server
        environment:
            - security_username=${security_username}
            - security_password=${security_password}
        networks:
            - msa-network

    service-product:
        build:
            context: ./keupang-product
        ports:
            - "8082:8082"
        depends_on:
            - eureka-server
            - config-server
        environment:
            - security_username=${security_username}
            - security_password=${security_password}
        networks:
            - msa-network

    eureka-server:
        build:
            context: ./keupang-eureka-server
        ports:
            - "8761:8761"
        networks:
            - msa-network
networks:
    msa-network:
        driver: bridge
  • 서비스 정의
    • 각 서비스는 context로 프로젝트 경로를 지정해 dockerfile을 참조한다
    • port로 미리 포트도 매핑해주었다. 
    • environment에서 환경 변수 설정
      • 해당 변수는 system에 등록하는 과정임
      • ${security_username}이라고 꺼내오는 것은 docker-compose와 동일한 경로의 .env 파일로 부터 가져오는 것이다.
  • 의존성 관리
    • depends_on 키워드로 서비스 간 의존성 설정
    • config server에서 정보를 가져오는 user나 product 프로젝트는 반드시 config server 이후에 실행 되어야 하므로 의존성 설정이 필수다.
  • 네트워크 구성
    • msa-network라는 공통 네트워크를 생성하여 모든 서비스가 통신 가능.
      • networks 설정: msa-network는 서비스 간 통신을 위한 bridge 네트워크로 설정함
      • 각 서비스는 컨테이너 내부에 생성된 가상의 동일한 네트워크를 공유하여 통신이 가능하다.
      • 개별 네트워크 설정 명령어 없이  위의 networks 설정으로 만들 수 있다.
        • 설정 안하면 default로 docker0 이라는 bridge 네트워크가 생김

4. Docker로 실행하기

실행 과정

서비스 빌드 및 실행

#서비스 빌드 및 실행
docker-compose up -d --build

실행 확인

  • 서비스가 정상적으로 실행되면 컨테이너 ID와 서비스 포트 등이 출력된다.
  • 실행이 잘 안된다면 아래에 트러블 슈팅에 해당사항있는지 확인하고 수정하기
#실행 확인
docker ps
#결과 확인
> docker ps
CONTAINER ID   IMAGE                     COMMAND               CREATED        STATUS        PORTS                    NAMES
2062db03250e   keupang-service-product   "java -jar app.jar"   23 hours ago   Up 23 hours   0.0.0.0:8082->8082/tcp   keupang-service-product-1
91eba52ce589   keupang-service-user      "java -jar app.jar"   23 hours ago   Up 23 hours   0.0.0.0:8081->8081/tcp   keupang-service-user-1
78fb69c6e387   keupang-api-gateway       "java -jar app.jar"   23 hours ago   Up 23 hours   0.0.0.0:8080->8080/tcp   keupang-api-gateway-1
9381352d986c   keupang-config-server     "java -jar app.jar"   23 hours ago   Up 23 hours   0.0.0.0:9000->9000/tcp   keupang-config-server-1
441651beef2d   keupang-eureka-server     "java -jar app.jar"   23 hours ago   Up 23 hours   0.0.0.0:8761->8761/tcp   keupang-eureka-server-1

네트워크 확인

  • 네트워크 설정은 자동 적용되며, 별도로 설정할 필요가 없다.
  • docker network inspect로 확인
#네트워크 확인
docker network inspect keupang_msa-network

#프로젝트 이름이 keupang이라서 그런지 내가 설정한 "msa-network" 앞에 "keupang_" 을 붙인 이름으로 네트워크가 생성되어 있다.
> docker network inspect keupang_msa-network
[
    {
        "Name": "keupang_msa-network",
        "Id": "93a2bd6b34ee02ae8fa2c3878620aea0ede3929c2a6d8f9584bddd061e88ebf9",
        "Created": "2024-11-26T09:36:47.913946257Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "2062db03250e73af47536ec039d2bf28715c950fdeee69bafe0ce76cda20a469": {
                "Name": "keupang-service-product-1",
                "EndpointID": "6d880bffe03578a365cca3810837254f3b63d55fb6584060909a48bacc1a490a",
                "MacAddress": "02:42:ac:12:00:04",
                "IPv4Address": "172.18.0.4/16",
                "IPv6Address": ""
            },
            "441651beef2dbab4d4cc0fb8f50b3b04f1045a5d3d067ec95bfb85e81984f660": {
                "Name": "keupang-eureka-server-1",
                "EndpointID": "7a11f2730213b9e99e424d6a1e3f21cf7efa89ed39f13069cec9f2009c5fc017",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "78fb69c6e387007e1bfe200f689dff13439b8f40a0b687b7b1585d28ae56928c": {
                "Name": "keupang-api-gateway-1",
                "EndpointID": "5e00c2fa0fbc7c78db7cfd3ce90c5effd6667f8b3918907d9a9397f73b6ee1ae",
                "MacAddress": "02:42:ac:12:00:05",
                "IPv4Address": "172.18.0.5/16",
                "IPv6Address": ""
            },
            "91eba52ce5894c9af2e1e5de474fd11fd6baaa3deab16525155490534c938add": {
                "Name": "keupang-service-user-1",
                "EndpointID": "349fad69cafd5a9d8bd4233a713035b6f51ef3dc26948064812b4e0edb3b277f",
                "MacAddress": "02:42:ac:12:00:06",
                "IPv4Address": "172.18.0.6/16",
                "IPv6Address": ""
            },
            "9381352d986cf50c63494d488e5629d3422855770027ef888718bbfaae497e02": {
                "Name": "keupang-config-server-1",
                "EndpointID": "ecc4071940ab635333ed8102fd70541cd85e79ccdde982e2bfe804d9cfd075ab",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "msa-network",
            "com.docker.compose.project": "keupang",
            "com.docker.compose.version": "2.29.7"
        }
    }
]

5. 트러블슈팅

docker-compose build 오류

상황

  • docker-compose.yml이 있는 폴더로 이동하여 build 하려 할 때 일부 모듈만 실행 되고 나머지는 종료되어 있음.
  • docker ps 로 실행중 인 컨테이너를 조회 해봤을 때 eureka-server 하나만 동작중이 었다.
  • 참고로 docker pa -a 를 사용하면 동작이 안된 컨테이너까지 확인할 수 있다.
  • docker logs <container_id> 로 동작이 안된 컨테이너의 id를 넣고 log을 확인하여 원인을 찾았다.

원인

  • 프로젝트들이 각각 build가 안되어 있어서 docker image로 복사할 jar 파일이 없었다.
  • 프로젝트 build 하려고 보니 추가 되지 않은 의존성이 있었다.
  • 기존에 Dontenv를 사용해서 .env 파일의 설정 값들을 가져오는 코드에서 build 오류가 나고 있었다.

해결 과정

우선 처음에 발견한 원인은 단순히 각각의 프로젝트들이 build 되지 않아서 생긴 문제였기 때문에 프로젝트로 이동해서 일일이 build 하면 해결 될 줄 알았다.

하지만 모든 프로젝트들이 build 하는 과정에서 오류가 났다.

 

우선 config-server에서 오류가 나고 있었다. 해당 프로젝트는 config server 의존성만 추가하여 springframework의 test 의존성이 빠져 있어서 build 오류가 나고 있었다. 

하지만 test 의존성을 추가해도

@Test
void contextLoads() {
}

test 자체에서 오류 발생. 이 시점에서는 오류 발생 원인을 찾지 못해서 주석처리하고 넘어감.

 

주석처리를 하고 나니 이번에는 기존에 Dotenv로 env 파일의 설정 값을 가져오는 부분에서 오류가 발생하고 있었다. 

docker를 사용하면서 docker-compose의 environment로 .env 의 값들을 이미 시스템에 등록해둬서 꺼내 사용하기만 하면 되는데 컨테이너가 된 상황에서 dotenv로 기존 경로의 .env에 접근하려하니 문제가 된 것 같았다.

 

기존 코드

@SpringBootApplication
@EnableConfigServer
public class KeupangConfigServerApplication {

    public static void main(String[] args) {
        Dotenv dotenv = Dotenv.configure().directory("./")  // .env 파일 경로 설정
            .load();
        // Base64 복호화
        String base64Key = dotenv.get("private_key");
        String privateKey = new String(Base64.getDecoder().decode(base64Key));

        System.setProperty("private_key", privateKey);
        SpringApplication.run(KeupangConfigServerApplication.class, args);
    }

}

 

변경된 코드

@SpringBootApplication
@EnableConfigServer
public class KeupangConfigServerApplication {

    public static void main(String[] args) {
        String base64Key = System.getenv("private_key");
        String privateKey = new String(Base64.getDecoder().decode(base64Key));

        System.setProperty("private_key", privateKey);
        SpringApplication.run(KeupangConfigServerApplication.class, args);
    }

}

그리고 이과정에서 아까 config-server의 test 코드에서 왜 오류가 나는지 문득 예측이 갔다.

test를 실행하기 위해서 컨텍스트가 load 될 때 application.yml에 system의 값을 담아서 git에 연결하는 과정이 생긴다. 이때 값이 제대로 전달 되지 않아서 그런건 아닌가 했다.

하지만 다시 생각해보면 eureka-server 에 접근하는 서비스들도 모두 테스트를 실행할 때, system에서 가져온 admin의 username와 password를 통해서 접근하는데 이건 테스트할 때 오류가 발생하지 않는다. 그래서 두 상황의 차이점을 찾아봄.

 

결과는 git 설정할 때 env->system 에 있는 값이 제대로 전달 안돼서 그런 것이 맞았는데, eureka에 접근하는 컨테이너(프로젝트) 에서의 테스트는 왜 테스트가 잘 됐는지에 대한 정확한 원인은 다음과 같다.

 

Git 관련 설정의 특별한 속성 바인딩

  • Spring Cloud Config Server는 spring.cloud.config.server.git 설정을 @ConfigurationProperties를 통해 바인딩한다.
  • 이 과정에서 속성이 정확히 제공되지 않으면, 초기 빈 생성 단계에서 바로 실패해버림.
    • 즉, spring.cloud.config.server.git의 uri, private-key 등이 정의되지 않으면 GitEnvironmentRepository 빈을 만들 수 없으므로 테스트 환경도 오류를 발생시키게 됨.

Git 설정의 무조건적 초기화

  • GitEnvironmentRepository는 Config Server의 필수 컴포넌트로 간주된다.
  • 이 빈은 @EnableConfigServer를 통해 Config Server가 초기화될 때 항상 로드된다.
    • 테스트 할 때도 당연히 이 빈이 초기화되기 때문에 설정 누락 시 즉시 예외가 발생한다.

Eureka와의 차이점

  • Eureka의 경우, 서비스 등록/검색은 런타임에서 작동한다.
    • Eureka 클라이언트는 부트스트랩 과정에서 등록 정보를 로드하지만, 이는 기본적으로 비동기로 작동하며 누락된 설정으로 인해 초기화 단계에서 테스트 실패로 이어지지 않는다.
    • 또한, Eureka 클라이언트는 기본적으로 fail-safe 동작을 하도록 설계되어 있어, Eureka 서버가 없어도 테스트가 진행될 수 있다.
  • 반면 Git 설정은 동기식으로 초기화되며, 비어 있는 설정 값이 바로 예외를 발생 시킨다.

Mock 비밀키 값은 왜 동작할까? (제일 궁금했음 어차피 Mock도 틀린 비밀키 값인데 왜 동작?)

  • mock-private-key와 같은 가짜 값은 타입과 필수 속성을 만족하기 때문에 초기 바인딩 시 예외를 피할 수 있다고 한다.
    • 예를 들어, spring.cloud.config.server.git.uri가 빈 값이면 오류가 발생하지만, mock-uri처럼 아무 값이라도 주어진다면 Spring Boot는 이 값을 허용한다.
    • 쉽게 말해서 이전에는 env->system 의 값을 가져오려 했는데 test 할 때는 이게 잘 안 돼서 빈 값이 들어가고, 자연스럽게 오류 난듯.
    • Config Server는 테스트를 실행할 때 실제 Git 서버와 연결하려 하지 않기 때문에, 값 자체는 중요한 문제가 되지 않는다고 한다.

Eureka에 서비스가 등록되지 않는 문제

상황

  • 모든 프로젝트가 build가 잘 되고, 이제 docker-compose를 build해서 이미지를 생성하고 실행하려 했다.
  • 모두 잘 등록되고 동작 중인 것을 확인하고 api-gateway의 포트인 8080에서 user 서비스와 product 서비스에 접근하려함
  • 오류 발생

원인

  • eureka-server에 user와 product 프로젝트가 client 로서 등록이 안되어 있었던 것을 확인함.

해결 과정

  • 기존에 eureka-client 에서 eureka-server와 연동 할 때는 localhost를 사용해도 무방했으나, docker를 사용하면 localhost 대신에 docker-compose에 등록한 이름인 eureka-server를 써줘야한다고 함.
  • 그 이유는 docker에서는 각각의 어플리케이션이 별도의 컨테이너로 격리되는데, 이때 고유한 네트워크 인터페이스를 가지게 되기 때문이다. 그래서 서로 독립적으로 실행함.
    • 이때 docker-compose.yml 에서 networks를 정의해서 컨테이너 간의 통신이 가능한 상황임.
    • 이때 컨테이너 각각의 이름이 DNS 역할을 하게됨.

여기서부터는 블로그 포스팅 이후에 발견한 오류 & 리팩토링 입니다.

여기서부터는 위에 올린 글과 코드가 달라집니다.

 

docker-compose 로 실행할 때 user가 config-server의 설정을 가져오지 못하는 오류

상황

docker-compose 로 실행할 때 user service에서 config-server에서 가져오는 정보인 포트번호를 제대로 가져오지 못함.

그래서 위에 있는 docker-compose에서 적어둔 8081 포트를 지정해주지 않으면 user service에 지정된 포트번호가 없어서 default로 8080 포트를 사용하게 됨.

그에 따라서 gateway의 포트 번호는 8080과 충돌이 일어나면서 오류가 발생함.

원인

docker-compose로 각각의 서비스들을 한번에 실행하게 되면서 문제가 됨.

물론 docker-compose.yml에서 user-service는 config-server가 실행된 이후에 실행되도록 depends on 설정을 해뒀음. (위에 docker-compose.yml 내용 참고)

 

하지만 그것 만으로는 config-server가 실행 되고 git repository에서 정보를 가져오는 시간까지 user-service의 실행을 지연시키지 못함.

위 그림과 같은 흐름으로 포트번호를 가져오지 못함.

해결 과정

user service에서 config-server에 접근할 때 오류가 나도 실행이 되게끔 하는 optional 설정을 지워 줘야함. 

기존 코드(application.yml)

spring:
    application:
        name: product
    profiles:
        active: dev
    config:
        import: optional:configserver:http://${security_username}:${security_password}@config-server:9000

여기 있는 optional: 을 지워 주기만 하면됨

변경된 코드(application.yml)

config:
    import: configserver:http://${security_username}:${security_password}@config-server:9000

이렇게 하면 설정을 못가져 오면 아예 오류를 내버리게 됨.

이제 docker-compose.yml에서 user-service가 실행되면서 오류가 나면 될 때까지 재실행하는 옵션을 주면 됨.

docker-compose.yml

service-user:
    deploy:
        mode: replicated
        restart_policy:
            condition: on-failure #추가 된 옵션 (위에 deploy 부터 추가 됨)
    depends_on:
        - eureka-server
        - config-server

이 프로젝트의 경우에는 service-user 에서 config-server의 설정을 가져올 때 포트 번호를 가져옴. 그래서 따로 포트 지정해준거 다 없애줘도 이제 잘 돌아감.

docker hub 활용 (리팩토링)

상황

docker-compose 를 활용해서 이후에 배포를 할 계획임. 

그런데 현재 상황에서 배포가 됐다고 가정할 때, 서버에서 실행을 하기 위해서는 다음과 같은 과정이 필요하다.

1. jar 파일을 만들기 위해서 build 한 뒤에 서버로 넘겨주기

2. 서버에 dockerfile을 넘겨 준다음에 image를 만들 준비를 한다.

3. docker-compose를 이용해서 build해서 image를 만든다.

4. docker-compose로 실행한다.

 

아주 귀찮은 과정이 필요하다.

아직은 로컬이라고 가정한 상황이지만 미래를 위해 리펙토링이 필요하다.

해결

서버에서도 당연히 인터넷을 사용할 수 있기 때문에 docker-hub 기능을 사용할 수 있다.

docker-hub는 간단히 말하면 image를 local에 저장하지 않고 따로 cloud 처럼 docker-hub에 저장해서 어디서나 가져올 수 있도록 하는 저장 공간이다.

이렇게 하면 과정이 좀더 단순해진다. 먼저 간단히 과정만 먼저 보여주면 다음과 같다.

1. jar 파일을 만들기 위해 build를 한다. -> 이제 서버로 넘겨줄 필요가 없다.

2. 만들어진 jar파일에 대해서 이미지 build하고 docker hub에 push 하기 -> 이것 또한 서버로 넘겨주는건 없다.

3. docker compose pull 해서 docker compose에 지정되어있는 image들을 docker hub에서 가져온다.

4. docker-compose로 실행한다.

 

이렇게 보면 과정이 비슷해보이지만 서버로 jar 파일이나 dockerfile은 전해줄 필요가 없다.

즉, 배포된 상황에서 수정사항이 있을 때는 그냥 hub에 새로 build한 image를 push하고 서버에서는 pull 한다음 실행만 하면 된다.

실제로 적용해보면 훨씬 시간이 단축됨.

 

해결 과정

이 글에서는 로컬을 기준으로 하므로 일단 로컬에서 docker hub로 이미지를 push하는 것과 (pull은 할필요 없음. 어차피 image 로컬에서 만든거니까) 직접 만든 image나 pull 받은 image를 가지고 어떻게 프로그램을 실행하는지만 포스팅할 예정.

 

1. docker hub에 로그인

  • 아마 docker desktop을 설치하고 실행중인 상황이라면 어떤 정보를 입력하지 않아도 바로 로그인이 될 것이다.
docker login

2. jar 파일 만들기

  • 이건 각 프로젝트 경로에 가서 build 해주면 됨.
  • 해당 프로젝트는 keupang 안에 여러 서비스가 있는 구조인데 keupang-user 프로젝트를 build 하려면 keupang/keupang-user로 들어 간다음 아래 명령어 수행 하면 됨.
./gradlew clean build

3. image build하고 docker hub에 push 하기

docker buildx build --platform linux/amd64,linux/arm64 -t playdodo/keupang-config-server:1.0 ./keupang-config-server --push
  • 명령어가 아주 길다. 편의상 image build도 하고 동시에 docker hub에 push도 하기위해서 하나에 압축 해버렸다.
  • 명령어를 보면 buildx build를 사용하고 플랫폼에다가 linux/amd64랑 linux/arm64 이렇게 두개를 지정한 것을 볼 수 있다.
    • 먼저 현재 로컬이 macOs (mac m3 pro 사용)이고, 이후 사용할 서버는 ubuntu로 계획하고 있다. 이때 build된 image의 type과 OS의 타입이 안맞으면 실행할 수 없다.
    • 이를 위해서 image에 mac에 맞는 platform인 linux/arm64와, ubuntu에 맞는 linux/amd64 를 모두 지정해 준다.
    • 플랫폼 설정을 여러개 하려면 buildx 라는 명령어를 사용해야 한다고 해서 사용했다.
  • 명령어 중간에 playdodo/keupang-config-server:1.0 이 있다.
    • playdodo 자리에는 본인의 docker 사용자 이름을 넣어야 한다.
    • keupang-config-servdr는 내가 사용할 image의 이름이다.
    • hub에 올리려면 태그가 있어야하는데 ':' 뒤에 붙인 1.0이 그런 태그를 의미한다.

  • 그리고 ./keupang-config-server 는 jar 파일이 있는 경로를 말한다.
    • 이건 어디서 명령어를 실행하느냐에 따라 다르지만 이 프로젝트 같은 경우는 keupang 안에 다 들어있는 구조라서 keupang 폴더에서 해당 경로만 바꿔 주면서 jar 위치를 선택해주면 편하다.
  • --push 를 붙여주면 docker Hub 에 push 된다.
    • docker-desktop 에서 hub에 등록된 것을 확인할 수 있다.
    • dockerhub 페이지에서도 확인 가능하다.
    • dockerhub 페이지를 보면 linux/arm64와 linux/amd64 버전으로 모두 사용가능한 image가 등록된 것을 확인할 수 있다

  • 이렇게 올라간걸 local에서 그냥 사용하면 된다. (같은 방식으로 서버에서도 가져다 쓰면 되는 방식)

4. docker hub에 올라간 image를 사용하도록 docker-compose.yml 수정

services:
    mysql:
        image: mysql:8.0.39
        container_name: service-mysql
        environment:
            MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
            MYSQL_DATABASE: ${USER_DB_NAME}
            TZ: Asia/Seoul
        ports:
            - "3307:${DB_PORT}"
        networks:
            - msa-network
    config-server:
        image: playdodo/keupang-config-server:1.0 #hub에 등록할 때 쓴 사용자이름이랑 image이름:태그
        container_name: keupang-config-server #실행하고 나서 만들어질 컨테이너의 이름
        platform: linux/arm64 #플랫폼 지정하기 -> ubuntu 환경에서는 linux/amd64로 수정
        ports:
            - "9000:9000"
        environment:
            - SPRING_PROFILES_ACTIVE=prod
            - private_key=${private_key}
        networks:
            - msa-network

    ##################################### 중간 생략 #####################################
    
networks:
    msa-network:
        driver: bridge

5. docker-compose.yml 실행

#docker-compose build로 이미 image를 만들었기 때문에 할 필요 없음 -> 아주 편하쥬

docker-compose up -d

6. 결론

Docker를 활용한 MSA의 장점

  • 손쉬운 실행: 다양한 서비스를 컨테이너화해서 쉽게 실행하고 관리 가능함.
  • 이식성: 로컬에서 테스트한 환경을 그대로 클라우드로 배포 가능함.

해결한 문제 요약

  • 테스트 컨텍스트 오류: @ActiveProfiles("test")와 application-test.yml 추가로 해결.
  • Eureka Client 연결 문제: Docker 환경에서 localhost 대신 eureka-server로 설정. 

8. 추가 참고자료

 

[MSA스터디] 4. 도커를 사용한 마이크로서비스 배포

이 책에서 사용하는 모든 커맨드는 맥OS 모하비 기반의 맥북 프로에서 실행된다. 그리고 나는 여전히 윈도우다 😅3장의 기술 요구사항을 충족해야 하며, 도커를 설치해야 한다 예제를 실행하려

velog.io