70 %
Chris Biscardi

Deploying a Discord test bot on Digital Ocean with Honeycomb

The Party Corgi Network Discord server is reaching a point where we need some automation. That comes in the flavor of a discord bot for us. In a perfect world I'd be connecting the discord websocket API over to AWS APIGateway websockets backed by lambdas. This is not a perfect world so we're using Docker and Digital Ocean.

tldr; the code

the bot

Our bot starts out pretty small. I've included Honeycomb because I want some insight into what happens while this bot is running. We set the transmission to "writer" so that the events get logged out to stdout. We'll switch this later in production.

index.js
JS
const Discord = require("discord.js");
const libhoney = require("libhoney");
const hny = new libhoney({
writeKey: process.env.HONEYCOMB_TOKEN || "asf",
dataset: "discord",
serviceName: "corgo-discord-bot",
transmission: "writer",
});
const CORGO_BOT_ID = "714618235458289804";
// Create an instance of a Discord client
const client = new Discord.Client();
/**
* The ready event is vital, it means that only _after_ this will your bot start reacting to information
* received from Discord
*/
client.on("ready", () => {
console.log("corgo ready!");
});
// Create an event listener for messages
client.on("message", (message) => {
let ev = hny.newEvent();
ev.add({ eventType: "message", authorId: message.author.id });
if (message.author.id === CORGO_BOT_ID) {
ev.addField("isBot", true);
ev.send();
return;
}
if (message.content === "!avatar") {
// If the message is "what is my avatar"
// Send the user's avatar URL
message.reply(message.author.displayAvatarURL());
ev.addField("avatar", true);
}
ev.send();
});
hny.sendNow({ booting: true });
// Log our bot in using the token from https://discordapp.com/developers/applications/me
client.login(process.env.DISCORD_TOKEN);

Dockerfile

We're basing our Dockerfile on a specific version of node (v14) and a specific version of alpine linux (3.11). Then we set the entrypoint to node index.js.

Dockerfile
dockerfile
FROM node:14.3.0-alpine3.11
COPY . /opt/bot
WORKDIR /opt/bot
RUN yarn
ENTRYPOINT node index.js

Docker and DO

I used the docker hub registry for testing because it was easy and I already had an account. We can build the dockerfile into an image and run a container based on that image using the following. Note that we also need to set the DISCORD_TOKEN env var, which I already had set in my environment so I passed it through.

sh
docker build -t biscarch/corgo-bot .
docker run -ite DISCORD_TOKEN=$DISCORD_TOKEN biscarch/corgo-bot

With the built image we can push it to the registry

sh
docker push biscarch/corgo-bot:latest

Then ssh into our digital ocean droplit. You'll need to get the IP address from the console and also have set up the droplit with an ssh key you have access to.

sh
ssh root@xxx.xx.xx.xx

Once in, we can pull and run to test.

sh
docker push biscarch/corgo-bot
docker run -ite DISCORD_TOKEN=$DISCORD_TOKEN biscarch/corgo-bot

You should see output that looks like this when messages get sent. This is the bare scaffolded honeycomb events. We'll make these more interesting later.

"{\"time\":\"2020-05-26T00:53:20.869Z\",\"samplerate\":1,\"data\":{\"booting\":true}}"
corgo ready!
"{\"time\":\"2020-05-26T00:53:37.052Z\",\"samplerate\":1,\"data\":{\"eventType\":\"message\",\"authorId\":\"103513724052082688\",\"avatar\":true}}"
"{\"time\":\"2020-05-26T00:53:37.156Z\",\"samplerate\":1,\"data\":{\"eventType\":\"message\",\"authorId\":\"714618235458289804\",\"isBot\":true}}"
"{\"time\":\"2020-05-26T00:53:41.696Z\",\"samplerate\":1,\"data\":{\"eventType\":\"message\",\"authorId\":\"681453482590339081\"}}"

If you ssh in again from a different terminal, a docker ps will show us what containers are running.

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fe5419ebf09b biscarch/corgo-bot "/bin/sh -c 'node in…" 8 hours ago Up 8 hours charming_swartz