| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
- 잡생각 정리글
- Noam Nisan
- Shimon Schocken
- 이득우의 게임수학
- 입출력과 사칙연산
- C
- 이득우
- 김진홍 옮김
- (주)책만
- https://insightbook.co.kr/
- unity6
- 게임 수학
- 데이터 통신과 컴퓨터 네트워크
- JavaScript
- C#
- 백준
- 메타버스
- BOJ
- 생능출판
- hanbit.co.kr
- 밑바닥부터 만드는 컴퓨팅 시스템 2판
- HANBIT Academy
- 박기현
- booksr.co.kr
- C++
- 일기
- 주우석
- 전공자를 위한 C언어 프로그래밍
- The Elements of Computing Systems 2/E
- 알고리즘
- Today
- Total
cyphen156
디스코드 봇 - 주크박스 봇 만들기 #7 봇 클라우드 서버에 올리기 With Azure VM / 애플리케이션 systemd서비스하기 본문
디스코드 봇 - 주크박스 봇 만들기 #7 봇 클라우드 서버에 올리기 With Azure VM / 애플리케이션 systemd서비스하기
cyphen156 2025. 8. 31. 17:17공부하긴 싫고 프로젝트도 조그맣게 하고싶어서 하는 프로젝트
이번 글은 공식 문서를 참고하여 작성됩니다.
Azure 설명서
Microsoft Azure cloud service를 사용하여 강력한 애플리케이션을 빌드하고 관리하는 방법을 알아봅니다. 설명서, 예제 코드, 자습서 등을 가져옵니다.
learn.microsoft.com
리눅스 시스템 서비스 관련해선 다음 글을 참고하였습니다.
[Linux] systemd란? (service 명령어, systemctl 명령어, init)
[Linux] systemd란? (service 명령어, systemctl 명령어, init)
리눅스를 조금이라도 사용해봤다면 항상 systemd라는 미지의 프로세스가 있다는 것을 눈치 챘을 것이다. PID1를 차지하고 있는 프로세스인 만큼 엄청 중요한 역할을 할 것만 같다. Systemd는 부팅부
etloveguitar.tistory.com
우선 시작은 Azure For Student로 시작한다.
나는 학교에서 MS Office For Student를 지원받고 잇기에 되나 해봣는데 일단 학교 인증만 되면 100$가량의 크레딧을 1년간 이용할 수 있게 해준다.
만약 학생 계정이 없다면 무료 체험계정으로 200$가량의 지원을 받을 수 있으니 그걸 사용하자.
나는 학생 계정이 끝나면 일반 무료체험계정으로 넘어가려고 학생 계정 먼저 사용했다.
Azure for Students - 체험 계정 크레딧 | Microsoft Azure
Azure for Students - 체험 계정 크레딧 | Microsoft Azure
Microsoft Azure for Students에서 체험 계정을 만들면 USD 100 크레딧을 받을 수 있습니다. 신용 카드가 필요 없으며 Azure 평가판 서비스를 12개월 동안 사용할 수 있습니다.
azure.microsoft.com
로그인 하면 다음과 같이 많은 기능들이 소개되는데 우리는 우선 클라우드 컴퓨팅이 사용할 기능이기 때문에 Docker 컨테이너 배포 또는 Node.js 앱 만들기 섹션에 필요한 기능이 있을 것 같다.

1.Docker/kubernetes
백엔드 서버를 다양한 환경에서 개발-배포 등의 다양한 기능을 제공해야 할 때 사용되는 가상화 솔루션이다.
제대로 구성되어 있는 환경에서는 현재 사용자의 환경이 Windows이든, Mac이든, Android든 상관 없이 동일한 환경을 제공받고, 호환성을 보장받을 수 있다는 장점이 있다.
2. Azure VM
Amazon의 AWS와 유사하게 Microsoft에서 제공하는 클라우드 컴퓨팅 서비스
가상 머신을 통해 사용자가 원하는 환경을 구성하고, 서비스를 24시간 내내 제공할 수 있으며 추가 모니터링 도구를 통해 백엔드 상태를 점검할 수 잇다는 장점이 있다.
도커/쿠버네티스의 단일 인스턴스라 볼 수 있다.
3. Azure App Service
VM에 올라갈 애플리케이션을 작성하는 기능
주로 웹 페이지/웹 앱 또는 웹 앱 서버(WAS)를 작성할 때 사용된다.
결정 : Azure VM
우리가 지원해야 하는 기능은 단순히 Node.js로 작성된 백엔드 로직을 24시간 내내 실행하고 있는 환경을 설정하는 것이니 Docker 컨테이너 환경까지는 필요하지 않다.
또한 이미 Discord.js를 통해 애플리케이션이 완성되어 있으니 우리가 사용해야 할 기능은 Azure VM으로 귀결된다.
추가적으로 Database나 Network, Authroization과 같은 기능들도 있지만 이 기능들 또한 애플리케이션을 개발할 때 이미 커스터마이징 되어 작성되 있으니 사용하지 않는다.
1. VM환경 구성하기
우선 홈으로 들어가서 가상머신 서비스를 눌러 VM서비스 페이지로 들어가서 가상머신을 하나 만들어준다.
사용할 가상머신은 보통은 리눅스 서버가 공짜니 Ubuntu Linux서버를 사용한다.
나중에 kali Linux도 써보고 싶다


윈도우즈 서버를 사용하려면 따로 결제 추가 설정이 필요하다.


디스크 크기 설정하기
서비스 될 가상환경의 옵션을 선택해야 한다. 보통 B시리즈나 D시리즈를 사용하곤 하는데 요금과 성능을 타협해야 한다.
차이점은 다음 링크에 소개되어있다.
가상 머신 크기 개요 - Azure Virtual Machines | Microsoft Learn
가상 머신 크기 개요 - Azure Virtual Machines
Azure의 가상 머신에 사용할 수 있는 다양한 인스턴스 크기를 나열합니다.
learn.microsoft.com

우리가 사용해야 될 기능은
- 가끔씩 입력으로 들어오는 사용자 커맨드 메세지
- 그리고 이걸 처리할 때 사용될 유튜브 검색에 필요한 약간의 코어 성능과
- 음성 스트리밍을 위한 YT-DLP 영상 파일에 대한 디코딩-인코딩
- 파일 입출력과 SHA-256 & AES-256 GCM 암호화/복호화까지로 CPU성능은 꽤 사용하지만 메모리를 많이 사용하지는 않는다.
다음은 커맨드를 넣엇을 때 사용되는 코어 가동률을 측정한것이다.
내 컴퓨터의 코어가 Ryzen 7800X 3D라서 멀티 코어 기준으로 사용률이 측정되서 상당히 낮은 퍼센트를 보이지만 비교를 하자면
Discord 자체적으로 1.5~2%대의 평균 사용률을 보이는데 Node.js 앱이 0%에서 고성능을 사용하는 추론모델과 플레이리스트 조작시에 높아야 0.3%의 사용률을 보인다.
이건 봇이 100개의 채널에 들어가서 스트리밍 이벤트가 상시로 발생하는 경우가 아니면 디스코드정도의 퍼포먼스를 잡아먹지 않는다는 소리다.
또한 사용하는 메모리는 30메가 바이트밖에 안된다. 디스크 IO 또한 거의 발생하지 않고 있다.
사용하게 될 가상머신 이미지 후보군은 다음과 같이 설정된다.

그런데 우리는 100크레딧을 1년동안 써야한다.
시간당 0.05$의 가격은 월 35$로 크레딧을 많이 사용한다.
그렇기 때문에 우리는 상시 CPU 사용을 풀 로드로 가용할 수 있는 D서비스가 아닌, B시리즈를 2개의 코어와 1GB의 데이터를 사용하는 가상머신을 선택하기로 한다.
최종적으로 B2Ats_v2를 사용한다.
이 서비스는 750시간 + 1년간의 크레딧 만큼 무료 서비스가 제공되니 월 8.54$ -> 12개월 딱 쓸수 있다.
관리자 계정 설정하기
애저 가상머신을 관리할 관리자 계정을 설정한다.
보안 인증은 SSH 공개키를 통한 접속과 ID/Password를 통한 암호 입력을 통해 접속할 수 있다.
암호 그룹은 일반적인 로그인 옵션이기 때문에
우리는 SSH 공개키를 사용한다.
사용자 이름은 ID에 해당하는 것이니 따로 설정해준다. 나도 안알려줄거다
공개키 원본의 경우 세 가지 옵션이 있다.
- 새 키 쌍 생성(선택)
- 키 이름을 지정하여 즉석에서 새로 만드는 방식이다.
- RSA SSH와 Ed25519 SSH라는 두 가지 형식이 있다.
- Azure에 저장된 기존 키 사용
- 이미 다른 서비스에 제공하기 위해 애저 계정에 저장된 키가 있는 경우 사용한다.
- 기존 퍼블릭 키 사용
- 기존에 사용하던 개인 공개키가 있는 경우 사용한다.
- 우리의 경우 SHA-256을 통해 생성된 .env에 저장된 키와 같은 것을 말한다.

데이터 암호화 키와 계정 암호화 키가 동일한 경우 심각한 문제를 초래할 수 있으므로 둘을 따로 격리하여 저장해야 한다.
인바운드 포트 규칙의 경우
일반 유저가 봇 서버에 접속하지는 않고, 디스코드와 봇이 서로 상호 통신만 하기 때문에
관리자의 암호화 접속을 위한 SSH 포트만 열어놓기로 하고, 필요해지면 추가하기로 한다.
디스크와 네트워의 경우 따로 옵션을 조작하지 않고 넘어간다.


다른 모든 옵션들도 조작하지않고 검토 + 만들기를 통해 만들면 유효성을 검사하고 만들수 있게 해준다

이렇게 새로 키 쌍 생성이 뜨는데 아까 만들기로한 관리자 접속용 SSH 보안키이다.
프라이빗 키 다운로드 받아서 노출되지 않는 어딘가에 저장해놓자.
{Keyname}.pem으로 다운로드 된다.
나는 아예 프로젝트와 무관한 디렉토리에 위치시키는 방식을 사용하도록 하겠다.

완료되면 이렇게 배포가 완료된다.


가상 머신에 원격 접속하기
이제 연결 버튼과 CMD를 통해 배포된 가상머신에 원격접속을 가하도록 하겠다.
1. 연결 버튼을 통한 접속
우선 액세스를 확인한 후, 아까 다운로드받앗던 .pem파일이 있는 위치를 경로로 설정해준다.
경로만 입력해주면 자동으로 바꿔주니까 뭐 건드리지 말


경로 설정한뒤에 액세스 다시 한번 확인해주고 난 후
SSH는 “다른 사용자/그룹이 이 키를 볼 수 없어야 한다” 는 조건이 있기 때문
아까 받은 키 파일의 속성을 약간 수정해준다.
- {Keyname}.pem 파일 → 우클릭 → 속성(Properties)
- 보안(Security) 탭 → 고급(Advanced)
- 권한 항목 중에서 Authenticated Users, Users, Everyone 등을 모두 제거
- 오직 현재 로그인한 본인 계정만 남기기
- 적용 후 닫기


우선 권한을 모두 지우기 위해 상속을 제거한 뒤 추가버튼을 누른다
그리고 고급에 들어가면 개체 유형을 찾을 수 있는데 다음과 같이 Users를 찾아내 읽기 및 실행 권한만 추가하고 적용한다.



CMD를 통해 SSH를 통해 VM에 명령을 타이핑해주면
대강 요론식으로 뜬다.
Welcome to Ubuntu 24.04.3 LTS (GNU/Linux 6.11.0-1018-azure x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Sun Aug 31 07:10:53 UTC 2025
System load: 0.08 Processes: 116
Usage of /: 5.6% of 28.02GB Users logged in: 0
Memory usage: 29% IPv4 address for eth0: 172.16.0.4
Swap usage: 0%
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
JukeBox-bot@Jukebox-bot:~$
이제 가상환경을 최신화 업데이트 해준다.
sudo apt update && sudo apt upgrade
이제 디스코드 봇을 배포하기 위해 Node.js를 우분투 VM에 설치해야 한다.
그리고 필수 개발 킷을 설치한다.
sudo apt install -y curl git build-essential
Node.js 설치하기
그새 LST가 22.18.0에서 22.19.0으로 버전업되었지만 하위 호환이 되는 구조이니 14.X버전 이상이기만 하면 상관 없다.
# Download and install nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
# in lieu of restarting the shell
\. "$HOME/.nvm/nvm.sh"
# Download and install Node.js:
nvm install 22
# Verify the Node.js version:
node -v # Should print "v22.19.0".
nvm current # Should print "v22.19.0".
# Verify npm version:
npm -v # Should print "10.9.3".
깃허브 레포지토리 복제 & 종속성 설치
git clone https://github.com/cyphen156/JukeBox-Bot.git
cd JukeBox-Bot
우리는 yarn을 사용하긴 했지만 linux 에서는 npm으로 종속성을 설치하기로한다.
npm install -g npm@11.5.2
npm install
그리고 이제 환경변수를 설정한다.
리눅스에서 파일 생성은 nano 에디터를 통해 생성하고
저장은 Ctrl+O
이후 파일 이름 맞는지 확인하고 Enter키 입력
파일 입출력 종료는 Ctrl+X
.env 파일 생성
nano .env
DISCORD_TOKEN=your_token_here
MASTER_KEY=your_master_key_here
config.json파일 생성
{
"token": "your Token Here",
"clientId": "your ClientIDHere",
"guildId": "your GuildIDHere"
}
실행 되는지 테스트하기
node index.js
성공적으로 완료 되었다면 다음과 같이 활성화 된다.

이제 24시간 운영되는 봇이 서버에 올라갔다.
정상작동되는지 플레이리스트 파일 입출력 확인하기
일단 생성은 제대로 된다.
스토리지를 한번 확인해보자
플레이리스트 디렉토리 내용물 확인하기

로그 파일 내부 확인하기

현재 원격 SSH 접속을 통해 노드 서버를 켯기 때문에 원격 접속이 끊어진다면 Node 서버 앱 또한 같이 꺼진다.
이것을 방지하기 위해선 VM 환경에 PM2 또는 systemd를 통해 데몬화 해야 한다.
간단하게 요약하자면
systemd는 리눅스 OS측에서 제공하는 서비스 관리이다.
PM2는 systemd를 Node.js환경에서 사용하기 쉽게 구성해놓은 라이브러리이다.
우리는 포트폴리오에서 운영 경험을 해보기 위해 좀 더 원시적이지만 강력한 방법인 systemd를 통해 서비스를 상시화 & 관리 하도록 하겠다.
/etc/systemd/system/jukebox-bot.service
sudo nano /etc/systemd/system/jukebox-bot.service
[Unit]
Description=Discord JukeBox Bot
After=network.target
[Service]
User=JukeBox-bot
WorkingDirectory=/home/JukeBox-bot/JukeBox-Bot
ExecStart=/home/JukeBox-bot/.nvm/versions/node/v22.19.0/bin/node index.js
Restart=always
RestartSec=10
EnvironmentFile=/home/JukeBox-bot/JukeBox-Bot/.env
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
그리고 다음 명령어를 차례대로 실행하면
JukeBox-bot@Jukebox-bot:~$ sudo systemctl daemon-reload
JukeBox-bot@Jukebox-bot:~$ sudo systemctl start jukebox-bot
JukeBox-bot@Jukebox-bot:~$ sudo systemctl enable jukebox-bot
JukeBox-bot@Jukebox-bot:~$ sudo systemctl status jukebox-bot
JukeBox-bot@Jukebox-bot:~$ journalctl -u jukebox-bot -f
이렇게 성공적으로 봇이 실행된 것을 확인할 수 있다.

이제 마지막으로 모든 서버에서 명령어를 사용할 수 있도록 명령어 커맨드를 글로벌로 배포한다.
node deploy-global.js

명령어가 제대로 배포 되었는지는 다음 글에서 포트폴리오를 만들면서 테스트 해보도록하겠다
운동가야지...
프로젝트 코드는 다음 레포지토리를 통해 제공됩니다.
cyphen156/JukeBox-Bot: ToyProject : Discord JukeBox-Bot
GitHub - cyphen156/JukeBox-Bot: ToyProject : Discord JukeBox-Bot
ToyProject : Discord JukeBox-Bot. Contribute to cyphen156/JukeBox-Bot development by creating an account on GitHub.
github.com
※ Windows VS Linux : 플랫폼 환경에 따른 yt-dlp binary 실행 호환 문제 발생
Windows 환경에서는 yt-dlp.exe를 음악 재생시 bin 디렉토리에서 가져와 실행했다.
그런데 Linux 환경에서는 이 exe파일이 압축 해제했을 때 바이너리 코드가 다르게 해석되어 play 명령어가 동작하지 않고 봇이 먹통이 되어 서비스가 종료 -> 자동 재실행 되는 문제가 발생했다.
그래서 리눅스 환경에서는
1. 전역 프로그램을 설치하고
2. Player 코드를 일부 수정하여 플랫폼 분기 코드를 추가하였다.
YT-DLP 프로그램 설치
sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp
sudo chmod a+rx /usr/local/bin/yt-dlp
코드 수정
components/player.js 일부 발췌
const ytdlpPath = process.env.YTDLP_PATH || (
process.platform === "win32"
? path.resolve(__dirname, "../bin/yt-dlp.exe")
: "yt-dlp"
);
에러 로그
Aug 31 13:46:55 Jukebox-bot node[7300]: ✅ Ready! Logged in as 주크박스 Bot#4534
Aug 31 13:49:22 Jukebox-bot node[7300]: node:events:497
Aug 31 13:49:22 Jukebox-bot node[7300]: throw er; // Unhandled 'error' event
Aug 31 13:49:22 Jukebox-bot node[7300]: ^
Aug 31 13:49:22 Jukebox-bot node[7300]: Error: spawn /home/JukeBox-bot/JukeBox-Bot/bin/yt-dlp.exe EACCES
Aug 31 13:49:22 Jukebox-bot node[7300]: at ChildProcess._handle.onexit (node:internal/child_process:285:19)
Aug 31 13:49:22 Jukebox-bot node[7300]: at onErrorNT (node:internal/child_process:483:16)
Aug 31 13:49:22 Jukebox-bot node[7300]: at process.processTicksAndRejections (node:internal/process/task_queues:90:21)
Aug 31 13:49:22 Jukebox-bot node[7300]: Emitted 'error' event on ChildProcess instance at:
Aug 31 13:49:22 Jukebox-bot node[7300]: at ChildProcess._handle.onexit (node:internal/child_process:291:12)
Aug 31 13:49:22 Jukebox-bot node[7300]: at onErrorNT (node:internal/child_process:483:16)
Aug 31 13:49:22 Jukebox-bot node[7300]: at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
Aug 31 13:49:22 Jukebox-bot node[7300]: errno: -13,
Aug 31 13:49:22 Jukebox-bot node[7300]: code: 'EACCES',
Aug 31 13:49:22 Jukebox-bot node[7300]: syscall: 'spawn /home/JukeBox-bot/JukeBox-Bot/bin/yt-dlp.exe',
Aug 31 13:49:22 Jukebox-bot node[7300]: path: '/home/JukeBox-bot/JukeBox-Bot/bin/yt-dlp.exe',
Aug 31 13:49:22 Jukebox-bot node[7300]: spawnargs: [
Aug 31 13:49:22 Jukebox-bot node[7300]: '-f',
Aug 31 13:49:22 Jukebox-bot node[7300]: 'bestaudio[acodec=opus][ext=webm]/bestaudio[acodec=opus]',
Aug 31 13:49:22 Jukebox-bot node[7300]: '--no-playlist',
Aug 31 13:49:22 Jukebox-bot node[7300]: '-q',
Aug 31 13:49:22 Jukebox-bot node[7300]: '-o',
Aug 31 13:49:22 Jukebox-bot node[7300]: '-',
Aug 31 13:49:22 Jukebox-bot node[7300]: 'https://www.youtube.com/watch?v=-khytEdnwDg'
Aug 31 13:49:22 Jukebox-bot node[7300]: ]
Aug 31 13:49:22 Jukebox-bot node[7300]: }
Aug 31 13:49:22 Jukebox-bot node[7300]: Node.js v22.19.0
Aug 31 13:49:22 Jukebox-bot systemd[1]: jukebox-bot.service: Main process exited, code=exited, status=1/FAILURE
Aug 31 13:49:22 Jukebox-bot systemd[1]: jukebox-bot.service: Failed with result 'exit-code'.
Aug 31 13:49:32 Jukebox-bot systemd[1]: jukebox-bot.service: Scheduled restart job, restart counter is at 4.
Aug 31 13:49:32 Jukebox-bot systemd[1]: Started jukebox-bot.service - Discord JukeBox Bot.
Aug 31 13:49:33 Jukebox-bot node[7319]: [dotenv@17.2.1] injecting env (0) from .env -- tip: ⚙️ write to custom object with { processEnv: myObject }
Aug 31 13:49:34 Jukebox-bot node[7319]: ✅ Ready! Logged in as 주크박스 Bot#4534'토이프로젝트 > 디스코드 주크박스 봇' 카테고리의 다른 글
| 디스코드 봇 - 주크박스 봇 만들기 #6 플레이리스트 저장 && 암호화 (3) | 2025.08.29 |
|---|---|
| 디스코드 봇 - 주크박스 봇 만들기 #5 복호화 → 암호화 재생 → 스트림 안정화 (6) | 2025.08.22 |
| 디스코드 봇 - 주크박스 만들기 #4 유튜브 연동하기 (3) | 2025.08.21 |
| 디스코드 봇 - 주크박스 만들기 #3 명령어 배포하기 (1) | 2025.08.19 |
| 디스코드 봇 - 주크박스 만들기 #2 봇 활성화 및 코드 적용하기 (8) | 2025.08.18 |
