Koyebで一人で複数アカウントを持ったら叱られた

こんにちは、ナナオです。 先日遊びで作ったkoyebのアカウントとは別にkoyebのアカウントを作ってデプロイしたら、この画面になりました。 We cannot offer you access to Koyeb Your account matches patterns often associated with violations of our Terms of Service While we cannot provide details about the reason(s) triggering this behavior, we have determined that providing access to Koyeb is not possible If you believe this is a bug, you can verify your identity 訳文は以下の通り。 Koyebへのアクセスを提供できません あなたのアカウントは、当社の利用規約に違反することが多いパターンと一致しています。 この動作を引き起こした理由の詳細についてはお答えできませんが、Koyebへのアクセスを提供することは不可能であると判断いたしました。 これがバグ(誤判定)だと思われる場合は、本人確認を行うことができます。 私の場合、一人で複数のアカウントを作って、無料プランで複数デプロイしようとしたこが原因ではないか、という結論に落ち着きました。 koyebの利用規約は以下の通りです。 Terms of Service | Koyeb 直接「同一人物が複数アカウントを使って複数のサービスをデプロイすることを禁じる」といった旨は書かれてはいませんが、一般常識としてそんなことするなよ、ということでしょうか。。 ...

2026年1月17日 · にあえん

Koyebで無料のDiscord Botを構築してみた

こんにちは、ナナオです。 サーバー維持費、気になりますよね。 今回は無料で使えるサービスでDiscordのBotを作っていきたいと思います。 初期設定 まずは土台作りとして、Discordとボットのコードを実装していきます。 Discord側の初期設定 以下のURLからデベロッパーコンソールにアクセスします。 Discord Developer Portal ログインすると以下の画面になります。 「New Application」をクリックして新しくアプリケーションを作成します。 作成したアプリケーションのBotタブに行き、Reset Tokenでトークンを発行し、コピーしておきます。 Message Content Intentもオンにしておきます。 これをしないとBotがメッセージを読むことができないです。 ボットをサーバーに招待します。 InstallationタブからGuild InstallのScopesにbotを追加し、権限を設定します。(ここ重要) 今回は管理者権限にしました。 Install Linkをコピーし、ブラウザに貼り付けます。 インストールに成功すると、以下のようなウィンドウが表示されます。 サーバー側にも通知が飛びます。 Pythonの実装 コードを書いていきましょう。 パッケージをUVで作成します。 uv init --package discord-bot-playground giboでignorefileに追記します。 gibo dump Python >> .gitignore .envファイルを作成し、先ほど作成したDiscord botのトークンを貼り付けておきます。 DISCORD_BOT_TOKEN="xxx..." 必要なライブラリを追加します。 uv add discord.py dotenv コードを書きます。 ここでは簡単なコマンド実行をしていきます。 デコレーターでめちゃくちゃ簡単に実装できます。 import os from dotenv import load_dotenv import discord load_dotenv() DISCORD_BOT_TOKEN = os.environ.get("DISCORD_BOT_TOKEN") DISCORD_GUILD_ID = int(os.environ.get("DISCORD_GUILD_ID")) guild_id = discord.Object(id=DISCORD_GUILD_ID) intents = discord.Intents.default() client = discord.Client(intents=intents) tree = discord.app_commands.CommandTree(client) @client.event async def on_ready(): await tree.sync(guild=guild_id) @tree.command() async def hello(interaction: discord.Interaction): """Says hello!""" await interaction.response.send_message(f"Hi, {interaction.user.mention}") client.run(DISCORD_BOT_TOKEN) ポイントとしてはon_readyでsyncする際にギルドIDをしているところです。 ...

2026年1月17日 · にあえん

Gemini CLIを使ってみる

こんにちは、ナナオです。 巷ではClaude Codeを使ったコーディングが流行っていますが、やはり気になるのはコスト。 ということで、今回は無料で使えるGeminiを使って快適なAIコーディング環境を構築していきたいと思います。 セットアップ まずはGemini CLIをインストールしていきます。 インストール方法は以下のリポジトリを参考にします。 GitHub - google-gemini/gemini-cli: An open-source AI agent that brings the power of Gemini directly into your terminal. brew install gemini-cli 早速任意のプロジェクトで以下のコマンドを実行しました。 ❯ gemini init Please set an Auth method in your /home/banan/.gemini/settings.json or specify one of the following environment variables before running: GEMINI_API_KEY, GOOGLE_GENAI_USE_VERTEXAI, GOOGLE_GENAI_USE_GCA おっと、GEMINI_API_KEYが設定されていないのでエラーになりました。 miseを使っているので、以下のように環境変数を設定します。 APIキーは以下から取得します。 Sign in - Google Accounts mise set -g GEMINI_API_KEY="xxx..." 再度実行します。 ❯ gemini init Error when talking to Gemini API Full report available at: /tmp/gemini-client-error-Turn.run-sendMessageStream-2026-01-13T09-51-13-224Z.json [API Error: You have exhausted your daily quota on this model.] An unexpected critical error occurred:[object Object] 一日に使用する上限に達していました。 ...

2026年1月16日 · にあえん

k8sでNFSを使ったストレージの動的プロビジョニングを実施する

こんにちは、ナナオです。 k8sを運用していて、永続ストレージが欲しくなるケース、ありますよね。 今回はそんな時に役立つ動的プロビジョニングを実施してみたいと思います。 動的プロビジョニングとは k8sで永続ストレージを使用するには、PVとPVCを作成する必要があります。 PVはストレージの接続方法やディレクトリパスを指定するリソースで、PVCはストレージとデプロイメントやポッドを繋ぐためのインターフェースのような役割を果たすリソースです。 ただ、ストレージが必要になるたびに毎回PVを作ってPVCを作って…とするのは面倒です。 その手間を減らしてくれるのが動的プロビジョニングになります。 動的プロビジョニングでは、一度ストレージの接続方法とディレクトリパスを指定してあげれば、あとは勝手にそのディレクトリ内でPVを作ってPVCと紐づけてくれます。 実践 早速実践してみましょう。 動的プロビジョニングを行うために以下のツールをhelmを使用してインストールします。 GitHub - kubernetes-sigs/nfs-subdir-external-provisioner: Dynamic sub-dir volume provisioner on a remote NFS server. helmは以下のコマンドでダウンロード可能です。 brew install helm また、helmによるインストールの管理にはhelmfileというツールを使用します。 GitHub - helmfile/helmfile: Declaratively deploy your Kubernetes manifests, Kustomize configs, and Charts as Helm releases. Generate all-in-one manifests for use with ArgoCD. こちらもダウンロードはbrewコマンドで一発で行えます。 brew install helmfile 準備が整いました。 以下のようにプロビジョナーを設定します。 nfs: server: 192.168.0.94 path: /k8s-data storageClass: name: nfs-client defaultClass: true # デフォルトのストレージクラスにする reclaimPolicy: Retain # PVC削除時にNASのデータを残すか(Retainなら残る) 先ほど実装したプロビジョナーの設定を参照するhelmfileを実装します。 repositories: - name: nfs-subdir-external-provisioner url: https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/ releases: - name: nfs-provisioner namespace: kube-system chart: nfs-subdir-external-provisioner/nfs-subdir-external-provisioner version: 4.0.18 values: - ./values/nfs-provisioner.yaml 実装したhelmfileを適用します。 ...

2026年1月15日 · にあえん

k3sでワーカー(エージェント)ノードを追加する

こんにちは、ナナオです。 前回の記事でk3sで複数のコントロールプレーンの構築ができました。 今回はまた2台ほど新たにPCをセッティングしたので、ワーカーを追加していきたいと思います。 なお、OSはすべてUbuntu Serverを使用しています。 ワーカーの追加 各ノードにアクセスし、以下のコマンドを実行します。 curl -sfL https://get.k3s.io | K3S_URL=https://<サーバーのIP>:6443 K3S_TOKEN=<トークン> sh - トークンはコントロールプレーンノードの/var/lib/rancher/k3s/server/node-tokenに格納されているものを使用します。 コマンドの実行に成功すると、kubectl get nodeの結果に追加したワーカーが追加されているはずです。 ❯ kubectl get node NAME STATUS ROLES AGE VERSION mouse1 Ready control-plane,etcd 43h v1.34.3+k3s1 nanaonuc6caysserver Ready control-plane,etcd 43h v1.34.3+k3s1 nuc2 Ready <none> 62s v1.34.3+k3s1 <- 追加されている!! thinkcentre1 Ready control-plane,etcd 45h v1.34.3+k3s1 ということで、もう一台にも同じコマンドを実行してあげます。 ❯ kubectl get node NAME STATUS ROLES AGE VERSION mouse1 Ready control-plane,etcd 43h v1.34.3+k3s1 nanaonuc6caysserver Ready control-plane,etcd 43h v1.34.3+k3s1 nuc2 Ready <none> 3m43s v1.34.3+k3s1 thinkcentle2 Ready <none> 41s v1.34.3+k3s1 thinkcentre1 Ready control-plane,etcd 45h v1.34.3+k3s1 …はい、コントロールプレーンの追加に比べたら驚くほど簡単にセットアップできました。 ...

2026年1月14日 · にあえん

図書館予約管理システムをk8sでデプロイする

こんにちは、ナナオです。 以前の記事で図書館予約管理システムの構築と自宅k8sサーバーの構築を行いました。 Seleniumで図書館の予約管理システムを作った streamlitで表を出力した おうちでk3sを使ってk8sを構築する 今回は構築したk8s環境に予約システムをデプロイしようと思います。 実装 まずはDockerイメージのプッシュです。 Dockerレジストリを何にしようか…というのが最初のポイントですが、docker.ioはプライベートリポジトリが1リポジトリしか使えないのでナシ。 ghcr.ioは自分がGithubアカウントがプロなのもあって2GBまでストレージ使えるのと月の通信量が10GBまでなら課金なしなので、ghcr.ioにします。 ということでイメージをビルドしていきます。 docker build -f docker/Dockerfile -t library-checker:0.1.0 . プッシュもやっちゃいましょう。 ここからはこのドキュメントを参照します。 https://docs.github.com/ja/packages/working-with-a-github-packages-registry/working-with-the-container-registry GitHub Container Registry(ghcr)でコンテナイメージを管理する #Docker - Qiita PATを発行し、以下のコマンドを実行します。 echo "<発行したPAT>" | docker login ghcr.io -u <username> --password-stdin ログインに成功したら、以下のコマンドでプッシュします。 docker push ghcr.io/NAMESPACE/IMAGE_NAME:latest 次にイメージのプルに必要な認証情報をクラスタに渡します。 kubectl create secret docker-registry ghcr-secret \ --docker-server=https://ghcr.io \ --docker-username=ユーザー名 \ --docker-password=PAT(ghp_xxxx...) \ --docker-email=メールアドレス また、定義していた.envもシークレットとして登録しておきます。 kubectl create secret generic library-checker-env --from-env-file=.env それでは、システムを動かすためのファイルを実装します。 apiVersion: apps/v1 kind: Deployment metadata: name: library-checker spec: replicas: 1 selector: matchLabels: app: library-checker template: metadata: labels: app: library-checker spec: imagePullSecrets: - name: ghcr-secret # 先ほどクラスタに設定したイメージのプルに必要な認証情報 containers: # --- 1. アプリ本体 (Streamlit等のUIを想定) --- - name: app image: ghcr.io/<ユーザー名>/library-checker:0.1.0 ports: - containerPort: 8501 env: - name: SELENIUM_URL value: "http://localhost:4444" # 同じPod内なのでlocalhostでOK # .envの内容は本来ConfigMapやSecretを使いますが、一旦直接指定か環境変数で対応 envFrom: - secretRef: name: library-checker-env # 先ほどデプロイしたシークレット # 生存確認 readinessProbe: httpGet: path: /healthz port: 8501 initialDelaySeconds: 5 periodSeconds: 5 livenessProbe: httpGet: path: /healthz port: 8501 initialDelaySeconds: 10 periodSeconds: 5 # --- 2. Selenium Chrome (サイドカー) --- - name: chrome image: selenium/standalone-chrome:4.39.0-20251212 ports: - containerPort: 4444 resources: limits: memory: "2Gi" cpu: "1000m" volumeMounts: - name: dshm mountPath: /dev/shm # 共有メモリ (/dev/shm) の不足によるクラッシュを防ぐ設定 volumes: - name: dshm emptyDir: medium: Memory --- # --- 3. 外部公開用サービス --- apiVersion: v1 kind: Service metadata: name: library-checker-service spec: type: NodePort selector: app: library-checker ports: - name: ui port: 8501 targetPort: 8501 nodePort: 30501 # 外部からアクセスするポート - name: selenium port: 4444 targetPort: 4444 nodePort: 30444 今回もGemini先生に頑張ってもらいました。 ...

2026年1月13日 · にあえん

k8sで複数ノードに対する操作をAnsibleで共通化する

こんにちは、ナナオです。 k8sを構築してからどう活用しようかいろいろやってるのですが、一つ面倒なのが「複数のノードへ同じことを適用」するという作業です。 今回はこれをAnsibleで共通化していこうと思います。 Ansibleとは Ansibleだけで書籍になるほどなので、ここではざっと書きます。 Amazon.co.jp: Ansible実践ガイド 第4版[基礎編] (impress top gear) : 北山 晋吾, 佐藤 学, 塚本 正隆, 畠中 幸司, 横地 晃: 本 Ansibleは構成管理ツールの一つで、目的は「環境構築の自動化」です。 ドキュメントを見ながら環境構築したり、shファイルを組んだりすると思いますが、こういった作業を一元的に管理するためのツールがAnsibleです。 そんなAnsibleの特徴としては「冪等性」が挙げられます。 これはつまり、手作業で作ったshでよくある「これを各サーバーで実行する」というようなものではなく、「各サーバーは~~という状態であるべき」というあるべき状態を定義できるという点にあります。 もちろん状態監視など実装的には複雑になるんですが、あるべき姿が定義できる状態って所謂システムの属人化を防ぐという観点からもとてもいいことですね! 環境構築 ではAnsibleをインストールしていきます。 homebrewがインストールされている環境であれば以下のコマンドでインストール可能です。 brew install ansible インストールできました。 最初の一歩 さて、何から始めればいいか。。 とりあえずチュートリアルも兼ねてhello world的なことをやりたい。 ということで以下のサイトを参考にまずはhosts.yamlを定義しました。 https://zenn.dev/y_mrok/books/ansible-no-tsukaikata/viewer/chapter5 とりあえずk8sで構築したノードは三台あるので、これらの情報をhosts.yamlとして落とし込みました。 --- all: vars: ansible_user: username ansible_password: password hosts: thinkcentle1: ansible_host: 192.168.0.x nuc1: ansible_host: 192.168.0.x mouse1: ansible_host: 192.168.0.x 定義出来たら先ほどインストールしたansibleコマンドで簡単なコマンドを書く環境で実行してみます。 ansible all -i hosts.yaml -m ansible.builtin.command -a "df -H" 結果が出力されました。テンション上がる~~ プレイブックの実装 さて、ではAnsibleのメイン機能と言えるプレイブックを実装していきます。 今回は各ノードからnfsを扱えるようにするのと、k8sで構築したDockerイメージ格納用のプライベートレジストリのURLを設定します。 (プライベートレジストリの構築に関してはまた別でブログを書こうと思っています!) ...

2026年1月12日 · にあえん

k8sでDockerイメージを格納するためのプライベートレジストリを構築する

こんにちは、ナナオです。 自宅にk8sを構築してからいろいろやりたいことが増えました。 ということで今回はk8sを使って自宅内で使えるプライベートレジストリの構築に挑戦してみました。 どうやって構築するか うちには以前ジャンクで買ったNASがあるので、このNASをストレージにしてDockerイメージを放り込めるようにしたいです。 NASにはNFSで接続できます。 一度NAS側にDockerイメージを放り込むためのディレクトリを作成しておきます。 私の場合WebUIで設定できました 次に先ほど作成したディレクトリを参照するPVとPVCを作っていきます。 apiVersion: v1 kind: PersistentVolume metadata: name: registry-pv spec: capacity: storage: 100Gi accessModes: - ReadWriteMany # 複数ノードから同時に読み書き可能 persistentVolumeReclaimPolicy: Retain storageClassName: nas nfs: server: 192.168.0.xx # NASのIPアドレス path: /docker-registry # NASの共有パス --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: registry-pvc namespace: kube-system spec: accessModes: - ReadWriteMany resources: requests: storage: 100Gi storageClassName: nas 作成したところ、エラーになりました。 │ Warning FailedScheduling 15m default-scheduler 0/3 nodes are available: persistentv │ │ olumeclaim "registry-pvc" not found. not found │ │ Warning FailedScheduling 15m default-scheduler running PreFilter plugin "VolumeBind │ │ ing": error getting PVC "kube-system/registry-pvc": could not find v1.PersistentVolumeClaim "kube-system │ │ /registry-pvc" │ │ Normal Scheduled 15m default-scheduler Successfully assigned kube-system/do │ │ cker-registry-85dbb54f6c-zmrkl to nanaonuc6caysserver │ │ Warning FailedMount 58s (x15 over 15m) kubelet MountVolume.SetUp failed for volume │ │ "registry-pv" : mount failed: exit status 32 │ │ Mounting command: mount │ │ Mounting arguments: -t nfs 192.168.0.94:/docker-registry /var/lib/kubelet/pods/1f2e1d4d-447c-4bcf-9987-c │ │ 930a2576654/volumes/kubernetes.io~nfs/registry-pv │ │ Output: mount: /var/lib/kubelet/pods/1f2e1d4d-447c-4bcf-9987-c930a2576654/volumes/kubernetes.io~nfs/regi │ │ stry-pv: bad option; for several filesystems (e.g. nfs, cifs) you might need a /sbin/mount.<type> helper │ │ program. │ │ dmesg(1) may have more information after failed mount system call. エラーのbad option; for several filesystems (e.g. nfs, cifs) you might need a /sbin/mount.<type> helperから、NFSを扱うためのツールセット各ノードにがインストールされていないことが原因だとわかりました。 ...

2026年1月11日 · にあえん

おうちでk3sを使ってk8sを構築する

こんにちは、ナナオです。 今日は家でk8sを構築した際のことを書いていこうと思います。 経緯 最近、よくハードオフ巡り(通称: ハドフ巡り)をしています。 というのも、ジャンクPCが好きなんですよね。 手ごろな価格のPCを見つけては、意味もなくUbuntu載せたりメモリ乗せ換えたりして、動かすようにするのが楽しいんです。 ただ、サーバーは増えてるのですが肝心の何に使うかっていうのが決まってないんですよね。(何のために増やしてんねん!) ということで、最近家で動かしておきたいサービスも増えたので(これとか)、この機会に家にk8sのノードを構築していこうと思います。 実装 まずは家にサーバーを建てます。 今回はジャンクで買ってきたPCを三台ほど使います。 デスク下に配置したPC。汚くてすみません。。 OSはUbuntu Server24.04を入れて、ssh接続できるところまでは確認済みです。 ここにk8sディストリビューションとして(k3s)[https://k3s.io/]を導入します。 k3sはとにかく軽量なk8sディストリビューションで、また導入コストも低いということでこれにしました。 また、可用性を考慮してコントロールプレーンを複数台構築して、ワーカーノードは後付けするようにしました。 まずは一台目に以下のコマンドを実行します。 手順はこちらのドキュメントを参照します。 curl -sfL https://get.k3s.io | sh - 構築出来たら早速システムのポッドを確認してみましょう。 $ kubectl get pod --namespace kube-system WARN[0000] Unable to read /etc/rancher/k3s/k3s.yaml, please start server with --write-kubeconfig-mode or --write-kubeconfig-group to modify kube config permissions error: error loading config file "/etc/rancher/k3s/k3s.yaml": open /etc/rancher/k3s/k3s.yaml: permission denied あら、権限エラーが出力されました。 ということで、sudoをつけて再度トライすると… $ sudo kubectl get pod --namespace kube-system NAME READY STATUS RESTARTS AGE coredns-7f496c8d7d-cdzf8 1/1 Running 0 8m32s helm-install-traefik-5ptvv 0/1 Completed 0 8m31s helm-install-traefik-crd-rdkbj 0/1 Completed 0 8m32s local-path-provisioner-578895bd58-6ntrr 1/1 Running 0 8m32s metrics-server-7b9c9c4b9c-brdnd 1/1 Running 0 8m32s svclb-traefik-74f79865-phf72 2/2 Running 0 8m28s traefik-6f5f87584-gqqvf 1/1 Running 0 8m13s ということで無事出力されました。 ...

2026年1月10日 · にあえん

k8sでクラスタ内アクセスするときのURL

k8s使っている人からしたら当たり前っちゃ当たり前かもしれないですが、備忘録として残しておきます。 URL 以下のような形式になっています。 <Service名>.<Namespace名>.svc.cluster.local 感想 思い出したときはここを見よう

2026年1月9日 · にあえん