Overview
모바일 앱 개발 환경에서 APK 빌드 후 테스터들에게 다운로드 링크를 전달하는 과정은 생각보다 번거롭다.
링크를 복사해서 Slack에 붙여넣고, 테스터들은 모바일에서 해당 링크를 직접 입력하거나 복사해야 하죠. 특히 긴 URL의 경우 실수로 잘못 입력할 가능성도 있다.
이러한 불편함을 해결하기 위해 APK 다운로드 링크를 QR 코드로 자동 변환하여 Slack 채널에 전송하는 봇을 개발했다. Jenkins 빌드가 완료되면 자동으로 QR 코드가 생성되어 Slack에 전송되고, 테스터들은 모바일로 QR 코드를 스캔하기만 하면 바로 APK를 다운로드할 수 있다.
이번 글에서는 Python Flask 기반의 Slack Bot을 구축하고 Kubernetes에 배포하는 전 과정을 공유하겠다.

slack 화면 예시

주요 기능
이 봇은 단순히 QR 코드를 생성하는 것을 넘어 실무에서 필요한 여러 기능을 포함하고 있다.
핵심 기능
- APK 링크 → QR 코드 자동 변환: URL을 QR 코드 이미지로 변환
- 다중 채널 동시 전송: 여러 Slack 채널에 동시에 QR 코드 전송
- QR 코드 커스터마이징: 색상, 크기 조절 가능
- 빌드 정보 표시: 빌드 번호, 다운로드 URL 포함
보안 및 안정성
- API 키 인증: CI/CD 파이프라인만 호출 가능하도록 인증 제공
- Rate Limiting: DoS 공격 방어 (분당 요청 제한)
- 자동 재시도: Slack API 일시적 장애 시 최대 3회 자동 재시도
- 구조화된 JSON 로깅: ELK Stack, Loki 연동 용이
개발자 친화적
- Swagger UI: 인터랙티브 API 문서 제공
- 상세한 Health Check: Slack 연결 상태 실시간 확인
- 다양한 엔드포인트: 단일/다중/전체 채널 전송 지원
시스템 아키텍처
Jenkins/GitLab CI/GitHub Actions
↓ (HTTP POST with X-API-Key)
Ingress (slack-qr-bot.concrit.us)
↓
Kubernetes Service
↓
Flask Application Pod
├─ API Key Authentication
├─ Rate Limiter
├─ JSON Logger
└─ Retry Logic (Tenacity)
↓
Slack API (files.upload_v2)
기술 스택
- 언어: Python 3.14
- 프레임워크: Flask 3.0 + Gunicorn
- 주요 라이브러리:
- slack-sdk - Slack API 통신
- qrcode[pil] - QR 코드 생성
- flasgger - Swagger API 문서
- flask-limiter - Rate Limiting
- tenacity - 재시도 로직
- python-json-logger - JSON 로깅
- 인프라: Docker, Kubernetes, GitLab CI, Harbor Registry
구현 과정
1. Slack App 설정
먼저 Slack API에서 새로운 앱을 생성하고 필요한 권한을 설정해야 한다.
필요한 Bot Token Scopes
- `chat:write` - 메시지 전송
- `files:write` - 파일 업로드
- `channels:read` - Public 채널 정보 조회
- `groups:read` - Private 채널 정보 조회
- `groups:write` - Private 채널 접근
앱을 워크스페이스에 설치한 후 Bot User OAuth Token을 복사해둔다. 형식은 `xoxb-` 로 시작한다.
만약 앱 추가 에러 가 발생 시 채널에 가서 아래의 명령어를 수행한다.
/invite @your-bot-name
- Scopes를 수정하게 되면 App을 Reinstall 해줘야 한다.
2. 프로젝트 구조
slack-qr-bot
├── Dockerfile
├── README.md
├── backup
│ └── app.py.bak
├── img
│ └── slack-qr-bot-example.png
├── k8s
│ ├── api-key-secret.yaml
│ ├── deployment.yaml
│ ├── harbor-robot-secret.yaml
│ └── slack-token-secret.yaml
├── requirements.txt
└── src
├── __init__.py
├── __pycache__
│ ├── __init__.cpython-313.pyc
│ ├── app.cpython-313.pyc
│ ├── config.cpython-313.pyc
│ ├── decorators.cpython-313.pyc
│ ├── services.cpython-313.pyc
│ └── utils.cpython-313.pyc
├── app.py
├── config.py
├── decorators.py
├── routes
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-313.pyc
│ │ ├── channels.cpython-313.pyc
│ │ ├── health.cpython-313.pyc
│ │ ├── qr.cpython-313.pyc
│ │ └── slack_events.cpython-313.pyc
│ ├── channels.py
│ ├── health.py
│ ├── qr.py
│ └── slack_events.py
├── services.py
└── utils.py
3. Python 코드 구현
4. Kubernetes 배포
5. GitLab CI/CD 파이프라인
자동화된 빌드 및 배포
- `src/` 폴더 내 파일 변경 시 자동 빌드
- Harbor Registry에 이미지 푸시
- 수동 또는 자동 배포 트리거
사용 방법
1. Jenkins에서 호출
Jenkins 파이프라인에서 APK 빌드 후 QR 코드를 자동으로 전송할 수 있다.
// Jenkinsfile
stage('Send QR to Slack') {
steps {
script {
sh '''
curl -X POST http://slack-qr-bot.somaz.link/generate-qr \
-H "Content-Type: application/json" \
-H "X-API-Key: ${SLACK_QR_BOT_API_KEY}" \
-d '{
"channel": "apk-qr-generator",
"apk_url": "https://example.com/app.apk",
"build_number": "1.0.0"
}'
'''
}
}
}
- apk_url은 apk 파일을 올릴 경로로 변경해주면 된다.
- 나머지 channel, build_number, post 주소 등은 전부 예시이다.
2. curl로 호출
curl -X POST http://slack-qr-bot.somaz.link/generate-qr \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key-here" \
-d '{
"channel": "apk-qr-generator",
"apk_url": "https://example.com/app.apk",
"build_number": "1.0.0"
}'
- channel name과 channel id 둘다 가능하다.
3. Swagger UI로 테스트
브라우저에서 `http://<slack bot url>/api-docs` 에 접속하면 모든 API를 인터랙티브하게 테스트할 수 있습니다.
- 우측 상단 "Authorize" 버튼 클릭
- API Key 입력
- 원하는 API 선택 후 "Try it out"
- 파라미터 입력 후 "Execute"

실행 결과
QR 코드가 Slack 채널에 다음과 같이 전송된다.

로컬 테스트 방법
Docker Build
docker build -f Dockerfile -t slack-bot:test .
Docker Run
# Slack Bot Token을 환경 변수로 설정하고 실행
docker run -d \
--name slack-qr-bot \
-p 8080:8080 \
-e API_KEY="api-key" \
-e SLACK_BOT_TOKEN="xoxb-your-token-here" \
slack-bot:test
# 로그 확인
docker logs -f slack-qr-bot
로컬 기능 테스트
헬스체크
curl http://localhost:8080/health | jq
채널 목록 조회
curl http://localhost:8080/channels | jq
채널 이름으로 조회
curl -X POST http://localhost:8080/generate-qr \
-H 'Content-Type: application/json' \
-H 'X-API-Key: api-key' \
-d '{
"apk_url": "https://example.com/test-app.apk",
"channel": "#apk-qr-generator",
"build_number": "1"
}'
채널 ID로 조회
# 채널 ID 사용 (C로 시작)
curl -X POST http://localhost:8080/generate-qr \
-H 'Content-Type: application/json' \
-H 'X-API-Key: api-key' \
-d '{
"apk_url": "https://example.com/test-app.apk",
"channel": "Cxxxxxxxxxx",
"build_number": "1"
}'
커스텀 qr 코드 생성
curl -X POST http://localhost:8080/generate-qr/custom \
-H 'Content-Type: application/json' \
-H 'X-API-Key: api-key' \
-d '{
"apk_url": "https://example.com/test-app.apk",
"channel": "#apk-qr-generator",
"build_number": "124",
"qr_options": {
"box_size": 15,
"border": 4,
"fill_color": "#FF0000",
"back_color": "#FFFFFF"
}
}' | jq

다중 채널 전송
curl -X POST http://localhost:8080/generate-qr/broadcast \
-H 'Content-Type: application/json' \
-H 'X-API-Key: api-key' \
-d '{
"apk_url": "https://example.com/test-app.apk",
"channels": ["#apk-qr-generator", "#test-channel"],
"build_number": "125"
}' | jq
모든 채널 전송
curl -X POST http://localhost:8080/generate-qr/broadcast-all \
-H 'Content-Type: application/json' \
-H 'X-API-Key: api-key' \
-d '{
"apk_url": "https://example.com/test-app.apk",
"build_number": "126"
}'
트러블슈팅
1. `channel_not_found` 에러
원인: Bot이 채널에 추가되지 않음
해결:
# Slack 채널에서 실행
/invite @APK QR Generator
- Private 채널의 경우 `groups:read`, `groups:write` 권한이 필요
2. 429 Too Many Requests 에러
원인: Rate Limit 초과
해결:
- 1분 대기 후 재시도
- 개발 환경: RATE_LIMIT_ENABLED=false로 비활성화
3. Slack API 일시적 장애
자동 재시도 로직이 최대 3회까지 시도한다 (2초 → 4초 → 8초 대기).
재시도 후에도 실패하면 로그를 확인하면 된다.
kubectl logs -f -n slack-bots deployment/slack-qr-bot
성능 및 모니터링
Rate Limiting 정책
| 엔드포인트 | 제한 | 용도 |
| 전역 기본값 | 10 req/min | 일반 호출 |
| `/generate-qr` | 20 req/min | 단일 채널 QR 생성 |
| `/generate-qr/broadcast` | 10 req/min | 다중 채널 전송 |
| `/generate-qr/broadcast-all` | 5 req/min | 전체 채널 전송 |
| `/health` | 제한 없음 | Health check |
구조화된 로깅
JSON 포맷으로 로그가 기록되어 ELK Stack이나 Loki에서 쉽게 분석할 수 있다.
{
"asctime": "2025-12-23 10:30:45",
"name": "src.app",
"levelname": "INFO",
"message": "QR code sent successfully",
"channel": "apk-qr-generator",
"file_id": "F07KP4R8E9S"
}
마무리
이번 프로젝트를 통해 모바일 앱 배포 과정을 크게 개선할 수 있었다.
Jenkins에서 APK를 빌드하면 자동으로 QR 코드가 Slack 채널에 전송되고, 테스터들은 모바일로 QR 코드만 스캔하면 바로 앱을 다운로드할 수 있게 되었다.
특히 다음과 같은 장점이 있었다.
- 편의성 향상: URL 복사/붙여넣기 없이 QR 스캔만으로 다운로드
- 실수 방지: 긴 URL 입력 시 발생할 수 있는 오타 제거
- 자동화: CI/CD 파이프라인에 완전히 통합
- 확장성: 다중 채널, 커스텀 QR 코드 등 다양한 기능 지원
- 안정성: API 인증, Rate Limiting, 자동 재시도 등 운영 환경 고려
앞으로는 다음과 같은 기능을 추가할 계획이다.
- APK 메타데이터 자동 추출 (버전, 빌드 날짜 등)
- QR 코드에 로고 삽입
- 다운로드 통계 추적
- 여러 플랫폼 지원 (iOS IPA, Web 배포 등)
이 봇이 비슷한 환경에서 작업하시는 분들에게 도움이 되었으면 좋겠다.
Reference
- Slack API Documentation
- Slack Python SDK
- QRCode Python Library
- Flask Documentation
- Flasgger (Swagger UI for Flask)
- Flask-Limiter
- Tenacity (Retry Library)
- Kubernetes Documentation
- Harbor Registry
- GitLab CI/CD
- https://github.com/somaz94/slack-qr-bot
Somaz | DevOps Engineer | Kubernetes & Cloud Infrastructure Specialist
'IaC > CI CD Tool' 카테고리의 다른 글
| GitLab Source Backup & Restore with rclone + Google Drive (0) | 2026.03.26 |
|---|---|
| GitLab CI/CD YAML 파일 최적화: 중복 제거와 재사용성 향상 (0) | 2026.03.17 |
| GitLab CI로 Google Drive에 자동 업로드하기 (0) | 2025.11.12 |
| GitLab 18.0 업그레이드 시 git_data_dirs 설정 변경 가이드 (2) | 2025.11.05 |
| Git 레포지토리 GitLab 마이그레이션 가이드 (2) | 2025.08.05 |