Memer Bot - Search & Create Memes
Tags: azuretrialhack, javascript, node, azure
Published: 2022-03-07 09:41:45

### Overview


***Memes are a way to take a little break from the stress of life and have a laugh.***

Hello everyone, today I will be sharing my fun tool called **"Memer Bot"**, which is a telegram bot that you can find here [Click Here](https://t.me/meme_mtwn105_bot).

Github link - [Click Here](https://github.com/mtwn105/memer-telegram-bot/)

I came across **The Microsoft Azure Trial Hackathon** on Dev.to and decided to participate in it by creating this small project.

---

#### Working of the bot

**Memer Bot** will let you search & create memes using thousands of templates & even your own custom images. 

Basically, there are three major features - 

- **/search ** command will let you search for a meme for a word/phrase (it will return the top meme if finds for that phrase)

- **/create** command will let you create memes using two options - a **Meme Template** or a **Custom Image**

Instructions are fairly straightforward while using these bots. 

At any point in time, if you feel, the bot is not responding, do try to use the **/reset** command and then try to do the operation again.

---

### Submission Category: 

***Computing Captains***

I have chosen **Computing Captains** category for this contest.
I have leveraged Azure's **Azure Kubernetes Service** for deploying this project.

---

### Tech Stack

I have used below tech stack to build Memer

#### Main Stack

- NodeJS
- Express (using as the main server)
- Redis (using as key-value database for user session management)
- Telebot (library to interact with Telegram API)

#### Devops

- Docker (for creating images of NodeJs express server)
- Kubernetes (using kubernetes via Azure Kubernetes Service to manage containers)

#### Third Party

- Telegram API (to communicate with users)
- Imgflip (to search & create memes)

---

### Architecture

Below is the basic architecture of the application:

![Memer_Architecture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fdympfriqs8ro9zzj8ao.png)

As you can see there are multiple components here:

1. **NodeJS Server** - Communicates with Telegram API & all third party APIs along with managing user sessions using Redis. It is deployed as a Docker container in a kubernetes pod on AKS.

2. **Redis** - Used to manage user states & sessions via key value pairs model. It is deployed as a Docker container in a kubernetes pod on AKS.

3. **Imgflip** - Used to search & create memes. Actual logic to search and create memes can be found in the GitHub repository.

4. **Telegram API** - Used to listen to user's messages & respond to them via Telebot library for NodeJS. 

---

### Deployment

To deploy Memer's backend & redis, I created a `Dockerfile` for NodeJS like this:

```Dockerfile
FROM node:latest

COPY package.json .
COPY package-lock.json .

RUN npm install

COPY . /

RUN npm install pm2 -g

RUN mkdir -p images

EXPOSE 3000

ENTRYPOINT npm run start
```
I built the docker image and pushed it to docker hub

```sh
docker build -t memer-bot .
docker tag memer-bot mtwn105/memer-bot
docker push mtwn105/memer-bot
```

I then use Azure's Azure Kubernetes Service to use this docker image & manage containers using Kubernetes.

I created a kubernetes cluster called **memer-k8s-cluster**

![Azure Kubernetes Cluser](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/by7biefz005zpeepess4.png)
 
Then I created Deployment configs for **Redis** & **NodeJS Express** like below:

**NodeJS**

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: memer-nodejs-express
  labels:
    app: memer-nodejs-express
spec:
  replicas: 1
  selector:
    matchLabels:
      app: memer-nodejs-express
  template:
    metadata:
      labels:
        app: memer-nodejs-express
    spec:
      containers:
        - name: memer-nodejs-express
          image: mtwn105/memer-bot:latest
          ports:
            - containerPort: 3000
          env:
            - name: APP_ENVIRONMENT
              valueFrom:
                secretKeyRef:
                  name: memer-secrets
                  key: APP_ENVIRONMENT
            - name: PORT
              valueFrom:
                secretKeyRef:
                  name: memer-secrets
                  key: PORT
            - name: TELEGRAM_KEY
              valueFrom:
                secretKeyRef:
                  name: memer-secrets
                  key: TELEGRAM_KEY
            - name: RAPID_API_KEY
              valueFrom:
                secretKeyRef:
                  name: memer-secrets
                  key: RAPID_API_KEY
            - name: IMGFLIP_USERNAME
              valueFrom:
                secretKeyRef:
                  name: memer-secrets
                  key: IMGFLIP_USERNAME
            - name: IMGFLIP_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: memer-secrets
                  key: IMGFLIP_PASSWORD
            - name: APP_URL
              valueFrom:
                secretKeyRef:
                  name: memer-secrets
                  key: APP_URL
            - name: GRAPH_JSON_API_KEY
              valueFrom:
                secretKeyRef:
                  name: memer-secrets
                  key: GRAPH_JSON_API_KEY
            - name: MY_CHAT_ID
              valueFrom:
                secretKeyRef:
                  name: memer-secrets
                  key: MY_CHAT_ID
            - name: REDIS_URL
              valueFrom:
                secretKeyRef:
                  name: memer-secrets
                  key: REDIS_URL
          imagePullPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: memer-nodejs-express
spec:
  selector:
    app: memer-nodejs-express
  ports:
    - port: 80
      targetPort: 3000
  type: LoadBalancer
```

**Redis**

```yaml
apiVersion: apps/v1 # API version
kind: Deployment
metadata:
  name: redis-master # Unique name for the deployment
  labels:
    app: redis # Labels to be applied to this deployment
spec:
  selector:
    matchLabels: # This deployment applies to the Pods matching these labels
      app: redis
      role: master
      tier: backend
  replicas: 1 # Run a single pod in the deployment
  template: # Template for the pods that will be created by this deployment
    metadata:
      labels: # Labels to be applied to the Pods in this deployment
        app: redis
        role: master
        tier: backend
    spec: # Spec for the container which will be run inside the Pod.
      containers:
        - name: master
          image: redis
          resources:
            requests:
              cpu: 100m
              memory: 100Mi
          ports:
            - containerPort: 6379

---
apiVersion: v1
kind: Service # Type of Kubernetes resource
metadata:
  name: redis-master # Name of the Kubernetes resource
  labels: # Labels that will be applied to this resource
    app: redis
    role: master
    tier: backend
spec:
  ports:
    - port: 6379 # Map incoming connections on port 6379 to the target port 6379 of the Pod
      targetPort: 6379
  selector: # Map any Pod with the specified labels to this service
    app: redis
    role: master
    tier: backend
```

I created a kubernetes secret to store necessary environment variables' values

```sh
kubectl create secret generic memer-secrets
kubectl edit secret memer-secrets
```

I now apply the kubernetes configurations

```sh
kubectl apply -f application.yaml
kubectl apply -f redis.yaml
```

That's it. Now if I run `kubectl get pods` I will all pods are successfully running.

```
NAME                                    READY   STATUS    RESTARTS   AGE
memer-nodejs-express-7db7c48bd5-8chd9   1/1     Running   0          31s
redis-master-85547b7b9-xbl5t            1/1     Running   0          3m24s
```
---

For more details do visit GitHub repo 👇

### GitHub

{% embed https://github.com/mtwn105/memer-telegram-bot/ %}