웹 클릭스트림 수집하기 1) 판 벌리기
카프카랑 하둡 써서 할만한 프로젝트 계획하기
무직 백수는 카프카랑 하둡을 어떻게 혼자 실습하지..?
데엔 취업 준비하는 백수인 저는 카프카와 하둡을 직접 사용해서 익히는 경험을 하고 싶어 아주 작은 PoC를 만들어보려고 합니다.
GPT의 도움을 받아, 어떤 프로젝트가 좋을지 고민하였고 실시간 웹 클릭스트림 로그 수집·저장·배치분석 파이프라인으로 정하였습니다.
🎯 PoC 목표
- 개인 블로그를 통해 클릭스트림 로그 데이터 생성
- 해당 클릭 로그를 Kafka에 실시간 전달
- Kafka Connect HDFS 커넥터를 이용해 토픽에 쌓인 메시지를 일정 주기(ex. 5분)로 HDFS에 파일로 저장
- HDFS에 적재된 로그 파일을 대상으로 배치 분석 실행
✅ 사전 준비
- 개인 블로그 먼저 준비: github.io 블로그
- 클릭 로그 받아줄 Ingest 서버 띄우기
- github pages 프론트에 JS 스니펫 심기
1. 개인 블로그 만들기
Jekyll 오픈소스 테마 chirpy를 포크해서 내 깃허브 페이지에 annmunju.github.io
레포지토리에 pages를 띄우는 과정입니다.
1.0 Jekyll 설치
M1 맥북을 사용하고 있어서 다음과 같은 게시글을 참고해 설치하였습니다.
1.1 Jekyll 테마 포크
chirpy-starter 레포에서 템플릿을 가져와 내 새로운 레포를 만듭니다.
1.2 로컬 클론 및 _config.yml 수정
1
2
git clone git@github.com:annmunju/annmunju.github.io.git
cd annmunju.github.io
위와 같이 경로 이동 후 _config.yml 파일에 필요한 정보를 넣어줍니다.
- url 추가 (깃허브 경로)
- 언어 변경: _data/locales에 ko-KR.yml 파일 추가, _config.yml 파일에 lang을 ko-KR로 수정
- timezone을 Asia/Seoul로 반영
- title, tagline, description 추가
- 트위터 삭제, github 추가, email과 링크 경로 수정
- 프리뷰 아바타 이미지 추가 (social_preview_image)
- 댓글 기능 추가 (disqus 계정 생성)
1 2 3 4
comments: provider: disqus disqus: shortname: annmunju-github-blog
1.3 github pages 설정
위의 chirpy-starter는 chripy라는 테마에서 가장 기본적인 사항만 적용된 버전입니다. 그렇지만 github actions 메니페스토 파일이 작성되어 있어서 github에 push하면 자동으로 배포(CD)할 수 있게 이미 설정되어 있습니다.
이를 적용하기 위해 github 레포 설정에 다음과 같이 배포 소스를 github actions로 설정해줍니다.
그럼 자동으로 main 혹은 master 브랜치로 push할 때 페이지가 배포 되는 것을 확인할 수 있습니다.
2. Ingest 서버 만들기
다음은 Ingest 서버 역할을 할 lambda를 생성합니다. 우선은 kafka를 사용하지 않고 단순하게 클릭스트림을 처리합니다.
우선 콘솔로 작업하고 이후에 구체적인 인프라 환경을 정의한 후 Terraform을 이용해 IaC로 관리할 계획입니다.
2.1 IAM 역할
람다는 CloudWatch Logs 작성 권한이 필요하기 때문에 필요한 권한을 추가한 역할을 생성합니다.
2.2 Lambda 함수
함수를 생성합니다.
함수의 내용은 다음과 같이 구성했습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import json
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
# API Gateway HTTP API를 사용하여 event['body']에 페이로드가 들어옵니다.
try:
payload = json.loads(event.get('body', '{}'))
except json.JSONDecodeError:
payload = {"raw": event.get('body')}
logger.info(f"Received click event: {payload}")
return {
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({"status": "ok", "received": payload})
}
2.3 API Gateway HTTP API 생성
이번엔 람다로 접근하기 위한 API 게이트웨이를 생성합니다. 우선 콘솔에서 API Gateway 검색 후 HTTP API로 api를 생성합니다. 자동 배포($default)를 적용해 람다가 수정되면 즉시 반영됩니다.
브라우저로 다른 도메인(프론트엔드)에서 API Gateway로 직접 요청할 때 보안 정책(CORS)에 의해 차단되지 않도록 허용 설정이 필요합니다. CORS 설정은 아래와 같이 진행합니다.
2.4 curl 테스트
1
2
3
4
curl -X POST \
-H "Content-Type: application/json" \
-d '{"path":"/test","tag":"A","id":null,"timestamp":"2025-05-21T12:00:00Z"}' \
https://{주소}.execute-api.ap-northeast-2.amazonaws.com/ingest
Invoke URL로 테스트해본 결과 정상 응답이 출력되는 것을 확인할 수 있었습니다. :)
1
2
# result
{"status": "ok", "received": {"path": "/test", "tag": "A", "id": null, "timestamp": "2025-05-21T12:00:00Z"}}
3. 프론트에 JS 스니펫 심기
지킬 테마를 사용하기 위해서 올린 정적 웹사이트에 JS 코드를 사용하려면 우선 직접 자바스크립트 코드를 _includes/ 폴더에 작성해야합니다.
3.1 _includes/clickstream.html 스니펫 파일 작성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- _includes/clickstream.html -->
{% if jekyll.environment == "production" %}
{% assign ingest_url = "INGEST_API_GATEWAY_URL" %}
{% else %}
{% assign ingest_url = "http://localhost:8000/ingest" %}
{% endif %}
<script>
document.addEventListener('click', event => {
const payload = {
path: window.location.pathname,
tag: event.target.tagName,
id: event.target.id || null,
timestamp: new Date().toISOString()
};
fetch("", {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
})
.catch(err => console.error('Ingest error:', err));
});
</script>
- “INGEST_API_GATEWAY_URL“는 github actions을 통해 secretes로 입력된 값으로 수정되도록 반영하기 위한 초기 값입니다.
- 개발 환경인 로컬에서 작업할 때는 fastapi로 작성한 코드로 테스트 합니다.
- 어떤 요소가 클릭되었는지 추적하기 위해 e.target 정보를 사용합니다.
3.2 레이아웃에 스니펫 인클루드
_layouts/home.html에 {% include clickstream.html %}
를 추가했습니다. 기존에 chirpy-starter는 해당 파일이 없고 자동으로 gemfile로 가져오므로 저는 jekyll-theme-chirpy에 home.html 파일을 가져와서 적용했습니다. 가장 하단에 paginator 전 줄에 추가했습니다.
1
2
3
4
5
6
7
8
9
10
...
</div>
<!-- #post-list -->
{% include clickstream.html %}
{% if paginator.total_pages > 1 %}
{% include post-paginator.html %}
{% endif %}
3.3 github actions에 Secrets 추가
_includes/clickstream.html 스니펫 파일에 적용된 “INGEST_API_GATEWAY_URL“는 github actions 수행시에 수정될 수 있게 실제 값을 변수(secrets)로 추가했습니다.
변수로 추가한 후 기존 github actions workflow 메니페스토 파일에
1
2
3
- name: Inject Ingest URL
run: |
sed -i "s#INGEST_API_GATEWAY_URL#$#g" _includes/clickstream.html
sed로 문자열을 변경하도록 위 내용을 빌드 전에 추가해 반영하도록 했습니다.
3.4 프론트엔드 검증 및 결과
블로그 준비는 지금 보고계신 이 창으로 모두 마쳤습니다. 이어서 구체적인 검증입니다.
-
브라우저 Network 탭 확인 GitHub Pages로 배포된 이 블로그에 접속한 뒤, 클릭 이벤트 발생 시
/ingest
로 POST 요청이 정상적으로 전송되는지 확인했습니다.
-
Lambda 로그(CW Logs) 확인 AWS 콘솔 → CloudWatch → 로그 그룹
/aws/lambda/clickstream-ingest
에서 실제 페이로드가 기록되었는지 확인했습니다.
🚀 결론 및 이후 계획
개인 블로그 클릭스트림 수집 준비는 다음과 같은 단계로 완성되었습니다.
- Jekyll 블로그에 JS 스니펫을 심어 클릭 이벤트를 캡처
- Lambda + HTTP API로 간단히 수집 → CloudWatch Logs에 기록
- GitHub Actions + Secrets를 활용해 프로덕션/개발 환경 분기 처리
앞으로는 이 데이터를 데이터 파이프라인으로 연결하기 위해 다음 과정을 진행할 예정입니다.
- Kafka 프로듀싱
- 배치 저장소 구성
- 분석 환경 구축
- 실시간 시각화
이 과정을 통해 “클릭스트림 로그 데이터 수집 → 빅데이터 분석” 흐름을 이해하고,
Kafka·Hadoop 기반의 데이터 엔지니어링 실력을 닦아보려고 합니다 :)