회사에서 한 일

docker-compose로 테스트 환경 구축하기

딤섬뮨 2024. 9. 8. 20:18
728x90

사내에서 기존에 1000줄에 달하는 복잡한 회원가입/로그인 기능 마이그레이션을 제안하고, 진행하게 되었다.
그를 위한 첫 단계로, 코드의 안정성을 보장하고 변화에 대응하기 위해 테스트 코드를 도입하게 되었다.
특히, 통합 테스트를 중심으로 시스템 전반의 정합성을 검증하고자 한다.
다음은 aws , db등 여러가지 환경에 얽혀있는 서버를 로컬에서 가장 간단히 테스트하기 위한 환경 구축기이다.


 

통합테스트란?

통합 테스트는 흔히 E2E(End to End) 테스트라고 불리며, 애플리케이션의 모든 계층을 거쳐 최종적인 기능이 올바르게 동작하는지 검증하는 방법입니다. 즉, 실제로 API 서버를 가동시킨 후 클라이언트가 서버에 요청을 보내고, 그 요청에 대한 응답이 예상한 결과와 일치하는지 확인하는 방식입니다.
 
ex. 정상 요청을 하면 200 상태 코드가 오는가?

describe('존재하지 않는 유저인 경우', () => {
  let uid;
  let adid;

  before(() => {
    id = uuidv4();
    password = Math.floor(Math.random() * 11);
  });

  it('id,password 가입을 성공한다', async () => {
    const res = await chai.request(app).post('/users').send({
      id,
      password,
    });

    expect(res).to.have.status(200);
    expect(res.body.result).to.have.property('token');
  });
});

 

테스트 환경 목표

  1. 로컬에서만 시행되는 환경
    1. 대부분 서버에 관한 서비스는 AWS 자원에 의존하고 있어 테스트를 위한 환경을 구성하는 데에 제약이 발생할 수 있습니다. AWS와 같은 외부 자원에 의존하는 테스트 환경은 테스트의 신속성을 떨어뜨리고, 개발 과정에서 불필요한 비용을 초래할 수 있습니다.
  2. 간단한 환경 실행
    1. 궁극적인 목표는 개발자가 가장 간단하게 테스트를 수행할 수 있는 환경을 만드는 것입니다. 실제로 docker-compose up 명령어 하나로 테스트 환경 구축을 할 수 있습니다.

 

Docker-Compose 를 사용한 인프라 구축

Docker Compose를 사용하여 로컬 환경에서 필요한 모든 인프라를 쉽게 설정할 수 있습니다.
컨테이너를 손쉽게 관리하고, 각각의 옵션과 환경을 제어할 수 있습니다.

  • 사용한 docker-compose.yml
services:
  mysql-docker:
    image: mysql:8
    command: --mysql-native-password=ON
    container_name: "mysql"
    volumes:
      - "./config:/docker-entrypoint-initdb.d"
    ports:
      - "3306:3306"
    environment:
      TZ: "Asia/Seoul"
      MYSQL_ROOT_PASSWORD: "root"

  redis-dokcer:
    image: redis:latest
    container_name: "redis"
    command: redis-server --port 6379
    ports:
      - "6379:6379"

  dynamodb-docker:
    entrypoint: [ "/bin/bash", "-c", "java -jar DynamoDBLocal.jar -sharedDb -dbPath ./data" ]
    image: "amazon/dynamodb-local:latest"
    container_name: dynamodb
    ports:
      - "8000:8000"
    volumes:
      - "./docker/dynamodb:/home/dynamodblocal/data"
    working_dir: /home/dynamodblocal
    healthcheck:
      test: [ "CMD-SHELL", '[ "$(curl -s -o /dev/null -I -w ''%{http_code}'' http://localhost:8000)" == "400" ]' ]
      interval: 10s
      timeout: 10s
      retries: 10

  dynamodb-local-setup:
    image: amazon/aws-cli
    depends_on:
      dynamodb-docker:
        condition: service_healthy
    volumes:
      - "./config/schema:/tmp/dynamo"
    environment:
      AWS_ACCESS_KEY_ID: 'FAKEID'
      AWS_SECRET_ACCESS_KEY: 'FAKEKEY'
      AWS_REGION: 'ap-northeast-1'
    entrypoint:
      - bash
    command:
      '-c "for f in /tmp/dynamo/*.json; do aws dynamodb create-table --endpoint-url "http://dynamodb-docker:8000" --cli-input-json file://"$${f#./}"; done"'

 
 

초기 스키마 설정 방안

로컬에서 테스트 데이터베이스를 사용하려면, 데이터베이스 스키마를 사전에 구축해야 합니다.
이 작업은 docker의 volume 옵션을 활용해 처리할 수 있습니다.
Volume이란?

  • Volume은 Docker 컨테이너 내부에서 로컬 파일을 사용할 수 있게 해주는 기능입니다. 이를 통해 로컬 파일을 컨테이너 내부에서 참조하거나, 데이터를 저장하는 데 사용할 수 있습니다.
  • Volume을 사용하면 Docker의 스토리지 내에 새로운 디렉토리가 생성되고, 해당 디렉토리의 권한은 Docker가 관리하게 됩니다.

Volume을 사용함으로써 컨테이너와 로컬 파일 시스템 간의 데이터를 쉽게 주고받을 수 있으며, 데이터의 영속성을 유지할 수 있습니다
 

MySQL 스키마 설정

MySQL 이미지는 docker 컨테이너 내부에 docker-entrypoint-initdb.d 위치에 .sql 파일이 있으면 컨테이너 실행 시 sql을 자동으로 실행해줍니다. [공식문서]

  1. 로컬의 특정 디렉토리 config에 초기 스키마 실행 DDL 파일을 추가합니다.
  2. docker-compose.yml의 volume 옵션을 선언합니다.
    • 다음 옵션은 config 디렉토리를 docker의 docker-entrypoint-initdb.d로 생성해줍니다
volumes:
      - "./config:/docker-entrypoint-initdb.d"

3. 실제 컨테이너가 실행되면, 도커 내부에 정상적으로 로컬 파일이 생성된 것을 볼 수 있습니다.

 

DynamoDB 스키마 설정

DynamoDB Local 이미지를 사용하여 로컬 환경에서 DynamoDB를 설정합니다.
DynamoDB의 스키마 설정은 AWS CLI를 통해 명령어를 실행해야만 가능합니다.
따라서, DynamoDB 컨테이너가 실행된 후 AWS CLI 이미지를 통해 스키마 설정 명령어를 실행해야 합니다. 컨테이너 간의 순서를 보장하기 위해 depends_on 옵션을 활용하여 DynamoDB 컨테이너가 정상적으로 실행된 후 AWS CLI 컨테이너가 동작하도록 설정할 수 있습니다.

  1. Health-Check 설정

healthcheck를 설정하여 DynamoDB 컨테이너가 정상적으로 동작하고 있는지 확인합니다. 10초마다 컨테이너에 HTTP 요청을 보내어 응답 상태가 400이면 정상으로 간주합니다.

healthcheck:
    test: [ "CMD-SHELL", '[ "$(curl -s -o /dev/null -I -w ''%{http_code}'' <http://localhost:8000>)" == "400" ]' ]
    interval: 10s
    timeout: 10s
    retries: 10

 2. depends_on 옵션 사용
depends_on 옵션을 사용하여 현재 서비스가 시작되기 전에 DynamoDB 컨테이너가 먼저 실행되고, 해당 컨테이너가 정상적으로 동작(health check 통과)하면 다른 서비스가 실행될 수 있도록 설정합니다.

depends_on:
    dynamodb-docker: //정의한 dynamodb 이미지 이름
      condition: service_healthy

 
3. AWS CLI를 사용한 스키마 설정
AWS CLI 이미지를 통해 DynamoDB 컨테이너가 실행된 후 스키마를 설정합니다.
command를 사용하여 create-table 명령어를 실행하여 테이블을 생성할 수 있습니다.

 dynamodb-local-setup:
    image: amazon/aws-cli
    depends_on:
      dynamodb-docker:
        condition: service_healthy
    volumes:
      - "./config/schema:/tmp/dynamo"
    environment:
      AWS_ACCESS_KEY_ID: 'FAKEID'
      AWS_SECRET_ACCESS_KEY: 'FAKEKEY'
      AWS_REGION: 'ap-northeast-1'
    entrypoint:
      - bash
    command:
      '-c "for f in /tmp/dynamo/*.json; do aws dynamodb create-table --endpoint-url "<http://dynamodb-docker:8000>" --cli-input-json file://"$${f#./}"; done"'

이렇게 docker-compose를 통해 개발자는 aws 와 관련 없이 $docker-compose up명령어로 로컬에서 간단하게 필요한 모든 환경을 구축할 수 있습니다.

728x90