사내에서 매 주마다 Google Sheets에 주간 보고를 하고있다. 보고서를 작성하지 않는 상황이 빈번하여 왜 그런가 생각해봤다.
필드 엔지니어의 특성 상 고객사로 출근하는 경우가 많고 퇴근 후에는 일이 손에 잡히지 않을 것이다.
근무 중에 모바일로 작성하면 될 것 같지만 개인적으로아이폰이라 그런지 모바일 환경에서는 줄 칸 바꾸기, 이동하기 등 작성하기가 너무 어려웠다. 구글 폼 입력처럼 텍스트를 제출하면 Google Sheets로 입력되는 간단한 서비스를 만들어보기로 했다.
구글 폼 입력 예시
Google Sheets API 사용하기 위해 먼저 GCP에 접속해서 프로젝트를 생성하고 Google Sheets API 서비스를 사용 신청하자
Google API 설정
생성된 프로젝트로 들어와서 API 및 서비스 항목으로 이동하여 API를 사용하기 위한 API키를 발급받고
Sheets API의 쓰기 기능을 사용하려면 Google 계정이 필요하므로 Oauth 클라이언트 ID도 만들어놓자
Google API 설정
HTML, CSS, JS는 잘 다루지 못한다. 그래서 Cursor에게 의뢰했다. index.html을 만들어줬고 해당 파일에 css, js 문법을 통째로 넣어서 node.js 기반 2000라인의 싱글 프로그램으로 만들어줬다. 수정의 수정을 반복하면서 나온 UI는 아래와 같다.
UI 완성 화면
목록 조회 버튼을 누르면 Google Sheets API를 통해 해당 시트의 정보를 읽어온 다음 매니저 이름과 사이트 이름을 드랍다운 형태로 보여준다. 보고서 제출 버튼을 누르면 보고서 작성 아래 텍스트 박스에 쓰여진 내용들을 API를 호출하여 Sheets에 입력한다.
해당 프로그램은 Docker Image로 빌드하여 도커 허브에 저장한 다음 사내에서 사용하는 Xen 가상 서버에서 구동했고 로컬에서 실행된 프로그램을 외부로 노출해주는 ngrok 서비스를 이용했다.
ngrok 서비스
ngrok에서 제공한 도메인을 통해 사용자가 접근하는 상황을 간단한 구성도를 그려보면 아래 그림과 같다.
구성도
Google Sheets API에서 쓰기 기능을 호출하려면 Google 계정 로그인이 필요하다. 해당 과정에서 리다이렉션이 일어나므로 위에서 만들었던 Oauth Client 설정에서 ngrok에서 제공해준 도메인을 "승인된 JavaScript 원본, 승인된 리디렉션 URI"에 등록하면 잘 동작한다.
후기
1. html에서 바로 API를 호출하므로 API키가 노출될 수 밖에 없었다. 최선으로는 API키의 호출 범위, 서비스 범위를 축소하는 방법으로 해결했다.
2. 원본 Sheets에 테스트를 할 수 없었기에 Sheets ID를 환경 변수로 선언하여 컨테이너를 올릴 때 환경변수를 주어 prod, dev 환경을 구분하여 진행하였다.
3. 도커에 올려서 진행하다보니 코드 수정으로 인한 CI/CD 구성이 필요했다. Git Action을 사용하여 Repository에 Commit이 Push될 경우 Docker Hub Repository에 Push되도록 파이프라인을 구성했다.
이번 글에서는 Kafka에서 데이터를 읽은 뒤 JSON 파일로 저장하던 Java 코드를 Elastic Search에 저장하도록 수정하자
지난 글에서는 Spring data elasticsearch 패키지 core 의존성을 찾을 수 없는 문제로 임시로 JSON 파일로 저장하도록 했다.
Cursor에게 계속해서 물어보고 수정하고 반복한 결과 데이터 전송 프로세스는 아래와 같다.
1.ElasticsearchOperations 주입
Spring Data ES 의 핵심 인터페이스로 ES와의 상호작용을 처리한다.
2. Kafka Listener을 통한 메세지 수신
listen 메서드로 topic에서 메세지를 수신한다.
3. 데이터 처리 및 문서 생성
정류장 이름 추가, 정류장 경유 여부 등 데이터를 가공하고 타임 스탬프, 고유 ID를 추가하여 ES에 저장하기 위한
문서 형식으로 새로 생성한다.
4. ES로 데이터 전송
IndexQueryBuilder() 메서드를 통해 현재 날짜 기반으로 인덱스를 생성하고 ElasticsearchOperations을 통해
문서를 ES에 저장한다.
ES에 잘 저장 되는지 로컬에서 Docker 컨테이너로 ES를 띄워서 테스트해보자
컨테이너를 생성할 때 인증서를 사용하지 않는 HTTP 요청으로 진행하기 위해 아래와 같이 환경변수 옵션을 줘서 실행한다.
위와 같이 Elastic Search Image로 컨테이너를 실행하고 자바 모듈을 실행한 후 ES 인덱스 조회 curl을 날려보면 인덱스 count가 증가한 것을 볼 수 있다.
curl -X GET "http://localhost:9200/_cat/indices/bus-location-2025-08-31?v"
curl -X GET "http://localhost:9200/bus-location-2025-08-31/_search?pretty"
현재는 로컬 테스트로 ssl 인증서 없이 통신을 진행했지만 처음 Java -> ES 연결을 시도할 때 인증서 관련 에러를 마주했다.
서비스에 사용되는 모듈은 모두 AWS VPC private subnet 환경에서 실행할 계획이여서 https 통신이 필요한지는 잘 모르겠다.