Project를 배포 해보자 #1

장준혁·2024년 2월 28일

AWS-EC2

목록 보기
1/2
post-thumbnail

지금 까지 프로젝트를 하면서 docker compose 환경에서 테스트 하면서 진행했던 작업들(빨간 영역 안에 있는 부분)을 배포 해보려고 한다.

모든 팀원들의 작업이 완료 되지 않아 전체를 배포하지는 못하지만 배포 경험도 쌓아볼 겸 현재 가지고 있는 작업물로만 진행 한다.

게시글을 작성하면서 진행 해볼 것이기 때문에 예외 발생 시에 해당 과정들도 정리 할 예정이다.

  • docker-compose.yml 파일에 환경 설정 작업을 한다.
  • compose 파일을 EC2에 업로드 한다.
  • compose 파일을 작동 및 배포 한다.

🐋 Docker Compose

🔍 ELK 설정

[ElasticSearch를 프로젝트에 적용 해보자] 게시글 에서 적용했던 방식을 벗어나지 않았다.
생략 하도록 하겠다.

💾 Redis 설정

  redis:
    container_name: dev_merona_redis
    image: redis:6.2.5
    command: redis-server
    restart: always
    networks:
      - dev_merona
    ports:
      - 6379:6379

redis 6.25버전을 사용하도록 명시 해줬으며 internel network dev_merona를 공유 하도록 설정 해줬다.
port는 host의 6379와 연동 했다.
dev_merona의 network를 공유 하도록 설정 했다.

🐰 RabbitMQ 설정

RabbitMQ SpringBoot 연동 하기 게시글에서 docker-compose가 아닌 docker명령어로 바로 실행 했었다.

  rabbitmq:
    image: rabbitmq:3.12.11
    container_name: dev_merona_rabbitmq
    restart: unless-stopped
    environment:
      - RABBITMQ_DEFAULT_USER=admin
      - RABBITMQ_DEFAULT_PASS=admin
    ports:
      - 5672:5672
      - 15672:15672
    command: rabbitmq-plugins enable rabbitmq_management

yml 파일로 변환 하여 테스트 했더니 접근이 가능하지 않았다.

  rabbitmq:
    image: rabbitmq:3.12.11-management
    container_name: dev_merona_rabbitmq
    restart: unless-stopped
    environment:
      - RABBITMQ_DEFAULT_USER=admin
      - RABBITMQ_DEFAULT_PASS=admin
    ports:
      - 5672:5672
      - 15672:15672

docker-compose환경에서 localhost:15672 관리 화면에 접속 하려면 image에 -management를 붙여주어 관리 플러그인 설정을 해줘야 했다.

관리 플러그인 설정이 되어있는 image를 pull 해서 오류를 해결 했다.

정상적으로 작동 한다.

🐬 Mysql 설정

  mysql:
    container_name: dev_merona_mysql
    image: mysql:8.0.22
    environment:
      MYSQL_DATABASE: dev_merona_mere
      # MySQL 데이터베이스의 이름을 dev_merona_mere로 설정
      MYSQL_ROOT_PASSWORD: {PASSWORD}
      MYSQL_ROOT_HOST: '%'
      # MySQL root 계정이 어떤 호스트에서든지 접근 가능하도록 설정
      TZ: 'Asia/Seoul'
      # 컨테이너의 시간대를 'Asia/Seoul'로 설정.
    ports:
      - 3306:3306
      # 호스트의 3306 포트와 컨테이너의 3306 포트를 연결
    volumes:
      - ./mysql-file/dev_merona_mere.sql:/docker-entrypoint-initdb.d/dev_merona_mere.sql
    networks:
      - dev_merona
    restart: always

를 yml파일에 설정하고 compose를 작동하니

java.sql.SQLSyntaxErrorException: Unknown database 'database'

에러가 발생 했다.

해당 에러를 확인해주기 위해 mysql 터미널로 진입해서 어떤 database가 있는지 확인을 시도 했다.
mysql 의 root로 진입해서

mysql 명령어 => show databases;

를 입력 후 dev_merona_mere라는 database가 존재 하는 것 을 확인 했다.

  mysql:
    container_name: dev_merona_mysql
    image: mysql:8.0.22
    environment:
      MYSQL_DATABASE: mere_test
      # MySQL 데이터베이스의 이름을 mere_test로 설정
      MYSQL_ROOT_PASSWORD: {PASSWORD}
      MYSQL_ROOT_HOST: '%'
      # MySQL root 계정이 어떤 호스트에서든지 접근 가능하도록 설정
      TZ: 'Asia/Seoul'
      # 컨테이너의 시간대를 'Asia/Seoul'로 설정.
    ports:
      - 3306:3306
      # 호스트의 3306 포트와 컨테이너의 3306 포트를 연결
    volumes:
      - ./mysql-file/dev_merona_mere.sql:/docker-entrypoint-initdb.d/dev_merona_mere.sql
    networks:
      - dev_merona
    restart: always

현재 spring boot프로젝트에서 설정된 database명은 mere_test이기 때문에 MYSQL_DATABASE: mere_test로 변경 해줬다.

하지만 예외는 변함 없이 발생했고 원인은 다른 곳에 있다고 생각했다.

java.sql.SQLSyntaxErrorException: Unknown database 'database'

만약 데이터 베이스명이 문제였다면 database가 아닌 mere_test라고 출력 되어야 하는데 뭔가가 이상했다.
spring boot 설정에 문제가 있는 것 같다고 의심이 들었다.

server:
    build:
      context: .
      dockerfile: Dockerfile_server
    container_name: dev_merona_spring_boot ## 컨테이너 이름
    restart: always ## 매번 프로젝트를 다시 실행한다. 
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/database?useSSL=false&allowPublicKeyRetrieval=true
      SPRING_DATASOURCE_USERNAME: {USERNAME}
      SPRING_DATASOURCE_PASSWORD: {PASSWORD}
      SPRING_REDIS_HOST: redis
      SPRING_REDIS_PORT: 6379
      SPRING_RABBITMQ_HOST: rabbitmq
      SPRING_RABBITMQ_PORT: 5672
      spring.profiles.active: local ## 스프링 active profile 설정
    ports:
      - 9091:9091
    depends_on: ## mysql, redis, rabbitmq를 실행 하고 server를 실행 하도록 한다.
      - mysql
      - redis
      - rabbitmq
    networks: ## internal network dev_merona를 공유
      - dev_merona

위 코드에서

SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/mere_test?useSSL=false&allowPublicKeyRetrieval=true

로 변경을 해서 database를 찾아가도록 재설정 해줬다.

기존에 구현해져 있던 API로 postman환경에서 mysql 더미데이터와 응답이 제대로 작동 하는지 테스트 했다.

정상적인 데이터의 반환을 확인 했다.

📚 Spring Boot 설정

server:
    build:
      context: .
      dockerfile: Dockerfile_server
    container_name: dev_merona_spring_boot ## 컨테이너 이름
    restart: always ## 매번 프로젝트를 다시 실행한다. 
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/mere_test?useSSL=false&allowPublicKeyRetrieval=true
      SPRING_DATASOURCE_USERNAME: {USERNAME}
      SPRING_DATASOURCE_PASSWORD: {PASSWORD}
      SPRING_REDIS_HOST: redis
      SPRING_REDIS_PORT: 6379
      SPRING_RABBITMQ_HOST: rabbitmq 
      SPRING_RABBITMQ_PORT: 5672     
      spring.profiles.active: local ## 스프링 active profile 설정
    ports:
      - 9091:9091
    depends_on:
      - mysql
      - redis
    networks:
      - dev_merona

CMD 환경에서 docker-compose up 명령어 입력 시에 예외가 발생 했다.

dev_merona_spring_boot  | 2024-02-27 16:13:06.804  INFO 1 --- [tContainer#0-17] o.s.a.r.c.CachingConnectionFactory       : Attempting to connect to: rabbitmq:5672
dev_merona_spring_boot  | 2024-02-27 16:13:14.806 ERROR 1 --- [tContainer#0-17] o.s.a.r.l.SimpleMessageListenerContainer : Failed to check/redeclare auto-delete queue(s).
dev_merona_spring_boot  | 2024-02-27 16:13:14.806  INFO 1 --- [tContainer#0-17] o.s.a.r.c.CachingConnectionFactory       : Attempting to connect to: rabbitmq:5672
dev_merona_spring_boot  | 2024-02-27 16:13:19.809  INFO 1 --- [tContainer#0-17] o.s.a.r.l.SimpleMessageListenerContainer : Restarting Consumer@6ac7c2de: tags=[[]], channel=null, acknowledgeMode=AUTO local queue size=0

localhost:15672에 접속하여 환경을 좀 찾아보니 queue자체가 존재 하지 않는 것을 확인했다.

새로운 이미지로 docker-compose를 작동 했으니 queue가 없는게 당연한 것이였다.

잘못 생각 했다.

  rabbitmq:
    image: rabbitmq:3.12.11
    container_name: dev_merona_rabbitmq
    restart: unless-stopped
    environment:
      - RABBITMQ_DEFAULT_USER=admin
      - RABBITMQ_DEFAULT_PASS=admin
    ports:
      - 5672:5672
      - 15672:15672
    command: rabbitmq-plugins enable rabbitmq_management

위와 같이 rabbitMQ를 설정 한 상태 였는데 network를 고려하지 않아서 발생한 문제였다.

container가 분리 되어 있음으로 동일한 network에서 작동 하도록 설정 해주고 포함 시켜야 되는 것 이였다.

networks:
  dev_merona:
    #네트워크 명

    driver: bridge

현재 설정은 internal network 설정 이지만 external network를 추천 한다.

internal network를 설정 하고 작동 시킨다면 docker 컨테이너가 내려갈 시에 network도 같이 내려간다,즉 dokcer network가 down될 우려가 있는 것이다.

해당 위험을 사전에 방지 하기 위해서는 docker internal network가 아닌 external network의 사용이 효과적일 것 같다.

--------------------------------------------------------
docker network 생성 명령어 => docker network create {network 명}
--------------------------------------------------------
docker-compose.yml파일에 저장

networks:
  {network 명}:
	external: true
--------------------------------------------------------

cmd에 network를 생성하는 명령어를 입력 후 yml 파일에 external network를 설정 한다.
driver: bridge 설정은 external 설정에서는 필요하지 않다.

📊 Prometheus 와 Grafana

  prometheus:
    container_name: dev_merona_prometheus
    image: prom/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yaml'
    volumes:
      - ./prometheus/prometheus.yaml:/etc/prometheus/prometheus.yaml
    ports:
      - 9090:9090
    networks:
      - dev_merona
    restart: always


  grafana:
    container_name: dev_merona_grafana
    image: grafana/grafana
    ports:
      - 3000:3000
    networks:
      - dev_merona
    restart: always

[Spring Boot 애플리케이션 시각화하기] 게시글에서 작성했던 내용과 동일하다.
위 게시글 에서는 docker compose를 사용하지 않고 docker 명령어로 바로 실행 했지만 작동 자체는 동일 하다.
dev_merona network를 공유 하도록 설정 했다.

localhost:9090으로 접속하면 prometheus 관리 화면을 볼 수 있고


localhost:3000으로 접속을 하면 grafana에 접속이 가능하다.

💽 최종

📝 docker-compose.yml

version: '3.2'

services:

  server:
    build:
      context: .
      dockerfile: Dockerfile_server
    container_name: dev_merona_spring_boot ## 컨테이너 이름
    restart: always ## 매번 프로젝트를 다시 실행한다. 
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/mere_test?useSSL=false&allowPublicKeyRetrieval=true
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: 1234
      SPRING_REDIS_HOST: redis
      SPRING_REDIS_PORT: 6379
      SPRING_RABBITMQ_HOST: rabbitmq
      SPRING_RABBITMQ_PORT: 5672
      SPRING_RABBITMQ_USERNAME: guest
      SPRING_RABBITMQ_PASSWORD: guest
      spring.profiles.active: local ## 스프링 active profile 설정
    ports:
      - 9091:9091
    depends_on:
      - mysql
      - redis
      - rabbitmq
    networks:
      - dev_merona

  elasticsearch:
    container_name: elasticsearch
    hostname: elasticsearch
    build:
      context: elasticsearch/
      args:
        ELK_VERSION: $ELK_VERSION
    volumes:
      - type: bind
        source: ./elasticsearch/config/elasticsearch.yml
        target: /usr/share/elasticsearch/config/elasticsearch.yml
        read_only: true
      - type: volume
        source: elasticsearch
        target: /usr/share/elasticsearch/data
    ports:
      - "9200:9200"
      - "9300:9300"
    environment:
      ES_JAVA_OPTS: "-Xmx256m -Xms256m"
      discovery.type: single-node
    networks:
      - dev_merona

  logstash:
    container_name: logstash
    hostname: logstash
    build:
      context: logstash/
      args:
        ELK_VERSION: $ELK_VERSION
    volumes:
      - type: bind
        source: ./logstash/config/logstash.yml
        target: /usr/share/logstash/config/logstash.yml
        read_only: false
      - type: bind
        source: ./logstash/pipeline
        target: /usr/share/logstash/pipeline
        read_only: false
      - type: bind
        source: ./logstash/config/pipelines.yml
        target: /usr/share/logstash/config/pipelines.yml
        read_only: false
    ports:
      - "5000:5000/tcp"
      - "5000:5000/udp"
      - "9600:9600"
    environment:
      LS_JAVA_OPTS: "-Xmx256m -Xms256m"
    networks:
      - dev_merona

  kibana:
    container_name: kibana
    hostname: kibana
    build:
      context: kibana/
      args:
        ELK_VERSION: $ELK_VERSION
    volumes:
      - type: bind
        source: ./kibana/config/kibana.yml
        target: /usr/share/kibana/config/kibana.yml
        read_only: false
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch
    networks:
      - dev_merona

  rabbitmq:
    image: rabbitmq:3.12.11-management
    hostname: rabbitmq
    container_name: dev_merona_rabbitmq
    restart: unless-stopped
    environment:
      - RABBITMQ_DEFAULT_USER=guest
      - RABBITMQ_DEFAULT_PASS=guest
    ports:
      - 5672:5672
      - 15672:15672
    networks:
      - dev_merona
  # rabbit image 버전 3.12.11
  # 5672작동 , 15672 시각화

  mysql:
    container_name: dev_merona_mysql
    image: mysql:8.0.22
    environment:
      MYSQL_DATABASE: mere_test
      # MySQL 데이터베이스의 이름을 dev_merona_mere로 설정
      MYSQL_ROOT_PASSWORD: 1234
      # MySQL의 root 계정 비밀번호를 1114로 설정
      MYSQL_ROOT_HOST: '%'
      # MySQL root 계정이 어떤 호스트에서든지 접근 가능하도록 설정
      TZ: 'Asia/Seoul'
      # 컨테이너의 시간대를 'Asia/Seoul'로 설정.
    ports:
      - 3306:3306
      # 호스트의 3306 포트와 컨테이너의 3306 포트를 연결
    volumes:
      - ./mysql-file/dev_merona_mere.sql:/docker-entrypoint-initdb.d/dev_merona_mere.sql
    networks:
      - dev_merona
    restart: always

  redis:
    container_name: dev_merona_redis
    image: redis:6.2.5
    command: redis-server
    restart: always
    networks:
      - dev_merona
    ports:
      - 6379:6379

  prometheus:
    container_name: dev_merona_prometheus
    image: prom/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yaml'
    volumes:
      - ./prometheus/prometheus.yaml:/etc/prometheus/prometheus.yaml
    ports:
      - 9090:9090
    networks:
      - dev_merona
    restart: always

  grafana:
    container_name: dev_merona_grafana
    image: grafana/grafana
    ports:
      - 3000:3000
    networks:
      - dev_merona
    restart: always

volumes:
  elasticsearch:


networks:
  dev_merona:
    #네트워크 명

    driver: bridge

📗 정리

작업했던 프로젝트를 docker compose로 묶어서 작동을 확인 해 봤다.

백엔드 API를 작업하던 시기 프론트엔드 개발자분들에게 API 테스트 환경을 넘겨주기 위해서 팀 리더가 infra 역할을 대신 자처 해서 환경을 구축 해줬다.
팀 리더도 잘 모르는 분야였는데 책임감 있게 작업 해줘서 지금도 감사한 마음을 가지고 있다.
당시 본인의 역량 부족으로 인해 팀 리더가 고생을 많이 했던 것 같다 미안하게 생각 하고 있다.;;

유데미에서 docker 관련 강의, 구글 자료 등을 찾아서 공부를 했는데 이해가 되지 않고 너무 어려워서 docker 작업에 유독 겁을 먹고 있었다.

docker에서 많은 부분을 고민하고 모르는 부분들은 개발바닥 3사로 에서 질문을 드렸더니 조언을 주셨다.
당시 제일 기억에 남는 주제는 "spring boot에서 rabbitMQ로 Chanel 연동이 되지 않습니다."라는 것이었다.

개발자 분은 "추가로 network도 따로 생성해서 external 네트워크로 명시적으로 도커 네트워크 구축해주세요" 라고 말씀 하셨는데 당시 본인은

networks:
  dev_merona:
    #네트워크 명

    driver: bridge

external network 인 줄 알았으며 rabbitMQ도 정상적으로 접속할 수 있었기 때문에 의문을 품지 않았다.
추후 알아보니 위 코드 설정은 docker 내부에서 설정하는 internal network이다.

감사 인사를 드리던 도중 조언 주셨던 개발자분이 "external로 만들라고 했는데 이유를 아시나요?" 말씀 하셨고 정확하게 이유를 답변 드리지 못했다.

게시글에 적었던 내용처럼 견문을 넓혀주는 답변을 해주셔서 압도적 감사의 마음을 가지고 있다.

docker compose를 local 환경에서 테스트 해봤으니 다음은 AWS에서 배포 작업을 시도 해볼 것이다.

감사한 마음을 가지면서 이번 게시글을 마무리 하겠다 😊

참고

https://velog.io/@lijahong/0%EB%B6%80%ED%84%B0-%EC%8B%9C%EC%9E%91%ED%95%98%EB%8A%94-Docker-%EA%B3%B5%EB%B6%80-Docker-Compose-Network-Volume-%EC%A0%95%EC%9D%98%ED%95%98%EA%B8%B0

profile
wkd86591247@gmail.com

0개의 댓글