feat(bot): 🚧 Start migrating to k8s.
This commit is contained in:
@@ -123,6 +123,7 @@ celerybeat.pid
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.env.shared
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
|
||||
Vendored
+4
-1
@@ -1,3 +1,6 @@
|
||||
{
|
||||
"conventionalCommits.scopes": ["bot", "db"]
|
||||
"conventionalCommits.scopes": ["bot", "db"],
|
||||
"yaml.schemas": {
|
||||
"kubernetes://schema/apps/v1%40deployment": "file:///c%3A/Users/rafab/Documents/Repos/Payphone-1/k8s.yml"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,4 +8,3 @@ RUN uv sync --no-dev
|
||||
RUN uv add uvloop
|
||||
|
||||
ENTRYPOINT [ "/bin/bash" ]
|
||||
CMD [ "run.sh" ]
|
||||
|
||||
@@ -1 +1,8 @@
|
||||
# Payphone
|
||||
# Payphone
|
||||
|
||||
Payphone is deployed using Kubernetes. To set up a local kubernetes cluster, you can use `minikube`.
|
||||
|
||||
```sh
|
||||
# To create a local cluster of 3 nodes:
|
||||
minikube start --network-plugin=cni --cni=calico --nodes=3
|
||||
```
|
||||
@@ -10,6 +10,7 @@ services:
|
||||
depends_on:
|
||||
- database
|
||||
- redis
|
||||
command: run.sh
|
||||
restart: always
|
||||
|
||||
database:
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: discord-bot
|
||||
labels:
|
||||
app: discord-bot
|
||||
spec:
|
||||
replicas: 11
|
||||
selector:
|
||||
matchLabels:
|
||||
app: discord-bot
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: discord-bot
|
||||
spec:
|
||||
containers:
|
||||
- name: bot
|
||||
image: nekidev/payphone:latest
|
||||
env:
|
||||
- name: IS_DEBUG
|
||||
value: "false"
|
||||
- name: SHARD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
- name: TOTAL_SHARDS
|
||||
value: "11"
|
||||
- name: REDIS_HOST
|
||||
value: "redis"
|
||||
- name: REDIS_PORT
|
||||
value: "6379"
|
||||
resources:
|
||||
limits:
|
||||
cpu: "500m"
|
||||
memory: "512Mi"
|
||||
requests:
|
||||
cpu: "250m"
|
||||
memory: "256Mi"
|
||||
restartPolicy: Always
|
||||
@@ -0,0 +1,57 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: citus-coordinator
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: citus
|
||||
role: coordinator
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: citus
|
||||
role: coordinator
|
||||
spec:
|
||||
containers:
|
||||
- name: coordinator
|
||||
image: citusdata/citus:latest
|
||||
env:
|
||||
- name: POSTGRES_DB
|
||||
value: "payphone"
|
||||
- name: POSTGRES_USER
|
||||
value: "payphone"
|
||||
- name: POSTGRES_PASSWORD
|
||||
value: "payphone"
|
||||
volumeMounts:
|
||||
- name: citus-coordinator-storage
|
||||
mountPath: /var/lib/postgresql/data
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
resources:
|
||||
requests:
|
||||
memory: "2Gi"
|
||||
cpu: "1"
|
||||
limits:
|
||||
memory: "2Gi"
|
||||
cpu: "2"
|
||||
volumes:
|
||||
- name: citus-coordinator-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: citus-coordinator-pvc
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: citus-coordinator
|
||||
spec:
|
||||
selector:
|
||||
app: citus
|
||||
role: coordinator
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
targetPort: 5432
|
||||
type: ClusterIP
|
||||
@@ -0,0 +1,22 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: citus-coordinator-pvc
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi # Change this size as needed
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: citus-worker-pvc
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi # Change this size as needed
|
||||
@@ -0,0 +1,63 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: citus-worker
|
||||
spec:
|
||||
replicas: 2 # Increase as needed for more workers
|
||||
selector:
|
||||
matchLabels:
|
||||
app: citus
|
||||
role: worker
|
||||
serviceName: citus-worker-headless
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: citus
|
||||
role: worker
|
||||
spec:
|
||||
containers:
|
||||
- name: worker
|
||||
image: citusdata/citus:latest
|
||||
env:
|
||||
- name: POSTGRES_DB
|
||||
value: "payphone"
|
||||
- name: POSTGRES_USER
|
||||
value: "payphone"
|
||||
- name: POSTGRES_PASSWORD
|
||||
value: "payphone"
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
resources:
|
||||
requests:
|
||||
memory: "2Gi"
|
||||
cpu: "1"
|
||||
limits:
|
||||
memory: "2Gi"
|
||||
cpu: "2"
|
||||
volumeMounts:
|
||||
- name: citus-worker-storage
|
||||
mountPath: /var/lib/postgresql/data
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: citus-worker-storage
|
||||
spec:
|
||||
accessModes: [ "ReadWriteOnce" ]
|
||||
storageClassName: "standard" # Update based on your storage class
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi # Size per worker
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: citus-worker-headless
|
||||
spec:
|
||||
selector:
|
||||
app: citus
|
||||
role: worker
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
targetPort: 5432
|
||||
clusterIP: None # Defines the service as headless, allowing direct pod DNS entries
|
||||
@@ -0,0 +1,40 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: redis
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: redis
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: redis
|
||||
spec:
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:7.4.1-alpine
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
resources:
|
||||
requests:
|
||||
memory: "1Gi"
|
||||
cpu: "1"
|
||||
limits:
|
||||
memory: "2Gi"
|
||||
cpu: "1"
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: redis
|
||||
spec:
|
||||
selector:
|
||||
app: redis
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 6379
|
||||
targetPort: 6379
|
||||
type: ClusterIP
|
||||
@@ -0,0 +1,2 @@
|
||||
45.134.39.59
|
||||
2.56.246.33
|
||||
+29
-21
@@ -28,9 +28,6 @@ from payphone.core import (
|
||||
)
|
||||
|
||||
|
||||
logging.setup()
|
||||
|
||||
|
||||
class Payphone(commands.AutoShardedBot):
|
||||
shutdown: managers.ValueProxy[bool]
|
||||
"""A value proxy that connects with all other shard processes.
|
||||
@@ -74,11 +71,34 @@ class Payphone(commands.AutoShardedBot):
|
||||
)
|
||||
|
||||
async def on_ready(self) -> None:
|
||||
"""Runs when the bot has finished initializing.
|
||||
"""
|
||||
"""Runs when the bot has finished initializing."""
|
||||
|
||||
self.log.info("Ready! Logged in as %s.", self.user.display_name)
|
||||
|
||||
async def set_presence(self, shard_id: int) -> None:
|
||||
"""Sets the presence of the bot back to online.
|
||||
|
||||
Args:
|
||||
shard_id (int): The ID of the shard to set the status for.
|
||||
"""
|
||||
|
||||
await self.change_presence(
|
||||
activity=discord.CustomActivity(
|
||||
name=f"Listening to p.help | Shard {shard_id + 1}"
|
||||
),
|
||||
status=discord.Status.online,
|
||||
shard_id=shard_id,
|
||||
)
|
||||
|
||||
async def on_shard_connect(self, shard_id: int) -> None:
|
||||
"""Runs when the shard connects.
|
||||
|
||||
Args:
|
||||
shard_id (int): The ID of the shard that connected.
|
||||
"""
|
||||
|
||||
self.log.info("Shard has connected.")
|
||||
|
||||
async def on_shard_ready(self, shard_id: int) -> None:
|
||||
"""Sets the activity for the shard.
|
||||
|
||||
@@ -86,15 +106,9 @@ class Payphone(commands.AutoShardedBot):
|
||||
shard_id (int): The ID of the initialized shard.
|
||||
"""
|
||||
|
||||
await self.change_presence(
|
||||
activity=discord.CustomActivity(
|
||||
name=f"Listening to p.help | Shard {shard_id + 1}"
|
||||
),
|
||||
status=discord.Status.online,
|
||||
shard_id=shard_id,
|
||||
)
|
||||
self.log.info("Shard is ready.")
|
||||
|
||||
self.log.info("Shard %s is ready!", shard_id)
|
||||
await self.set_presence(shard_id)
|
||||
|
||||
async def on_shard_resumed(self, shard_id: int) -> None:
|
||||
"""Sets the activity for the shard.
|
||||
@@ -103,15 +117,9 @@ class Payphone(commands.AutoShardedBot):
|
||||
shard_id (int): The ID of the resumed shard.
|
||||
"""
|
||||
|
||||
await self.change_presence(
|
||||
activity=discord.CustomActivity(
|
||||
name=f"Listening to p.help | Shard {shard_id + 1}"
|
||||
),
|
||||
status=discord.Status.online,
|
||||
shard_id=shard_id,
|
||||
)
|
||||
self.log.info("Shard has resumed.")
|
||||
|
||||
self.log.info("Shard %s was resumed!", shard_id)
|
||||
await self.set_presence(shard_id)
|
||||
|
||||
async def get_or_fetch_channel(
|
||||
self, channel_id: int
|
||||
|
||||
+29
-10
@@ -3,17 +3,36 @@ import logging
|
||||
from rich import logging as rlogging
|
||||
|
||||
|
||||
FORMAT = "%(message)s"
|
||||
|
||||
handler = rlogging.RichHandler(level=logging.INFO, rich_tracebacks=True)
|
||||
|
||||
formatter = logging.Formatter(FORMAT)
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
logger = logging.getLogger("payphone")
|
||||
|
||||
|
||||
def setup():
|
||||
"""Sets up pycord logging."""
|
||||
def _get_handler(process_name: str, module: str | None = None) -> None:
|
||||
"""Generates a handler for the given process name and module.
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG, handlers=[handler])
|
||||
Args:
|
||||
process_name (str): The process name.
|
||||
module (str | None, optional): The module inside the process. Defaults to None.
|
||||
"""
|
||||
|
||||
fmt = f"[blue][{process_name}{f": [green]{module}[/green]" if module is not None else ""}][/blue] %(message)s"
|
||||
formatter = logging.Formatter(fmt)
|
||||
|
||||
handler = rlogging.RichHandler(
|
||||
level=logging.INFO, markup=True, rich_tracebacks=True
|
||||
)
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
return handler
|
||||
|
||||
|
||||
def setup(process_name: str):
|
||||
"""Sets up pycord logging.
|
||||
|
||||
Args:
|
||||
process_name (str): The name of the process.
|
||||
"""
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG, handlers=[_get_handler(process_name)])
|
||||
|
||||
logging.getLogger("asyncio").addHandler(_get_handler(process_name, "asyncio"))
|
||||
logging.getLogger("discord").addHandler(_get_handler(process_name, "discord"))
|
||||
|
||||
@@ -117,9 +117,12 @@ async def loop() -> None:
|
||||
import asyncio
|
||||
|
||||
from payphone.db import setup
|
||||
from payphone.core import logging
|
||||
|
||||
await setup.init()
|
||||
|
||||
logging.setup("Flushing")
|
||||
|
||||
try:
|
||||
while True:
|
||||
await asyncio.sleep(30)
|
||||
|
||||
@@ -7,7 +7,6 @@ requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"aerich==0.7.1",
|
||||
"aiohttp>=3.10.10",
|
||||
"click>=8.1.7",
|
||||
"colorthief>=0.2.1",
|
||||
"httpx>=0.27.2",
|
||||
"orjson>=3.10.7",
|
||||
|
||||
@@ -5,8 +5,6 @@ from datetime import datetime, timezone
|
||||
from payphone.core import logging
|
||||
|
||||
|
||||
logging.setup()
|
||||
|
||||
log = logging.logger
|
||||
|
||||
|
||||
@@ -28,13 +26,15 @@ def shard(
|
||||
|
||||
from payphone.db import setup
|
||||
from payphone.bot import bot
|
||||
from payphone.core import config
|
||||
from payphone.core import config, logging
|
||||
|
||||
bot.shard_ids = [shard_id]
|
||||
bot.shard_count = shard_count
|
||||
bot.shutdown = shutdown
|
||||
bot.scheduled_shutdown = scheduled_shutdown
|
||||
|
||||
logging.setup(f"Shard {shard_id}")
|
||||
|
||||
log.info("Running shard %s with default loop.", shard_id)
|
||||
|
||||
bot.loop.set_debug(True)
|
||||
@@ -84,6 +84,8 @@ if __name__ == "__main__":
|
||||
from payphone.db import setup, models
|
||||
from payphone.core import config
|
||||
|
||||
logging.setup("Payphone")
|
||||
|
||||
redis = aredis.Redis(host="localhost" if config.IS_DEBUG else "redis")
|
||||
|
||||
async def init():
|
||||
|
||||
@@ -392,7 +392,6 @@ source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "aerich" },
|
||||
{ name = "aiohttp" },
|
||||
{ name = "click" },
|
||||
{ name = "colorthief" },
|
||||
{ name = "httpx" },
|
||||
{ name = "orjson" },
|
||||
@@ -407,7 +406,6 @@ dependencies = [
|
||||
requires-dist = [
|
||||
{ name = "aerich", specifier = "==0.7.1" },
|
||||
{ name = "aiohttp", specifier = ">=3.10.10" },
|
||||
{ name = "click", specifier = ">=8.1.7" },
|
||||
{ name = "colorthief", specifier = ">=0.2.1" },
|
||||
{ name = "httpx", specifier = ">=0.27.2" },
|
||||
{ name = "orjson", specifier = ">=3.10.7" },
|
||||
|
||||
Reference in New Issue
Block a user