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日 · にあえん

streamlitで表を出力した

こんにちは、ナナオです。 前回の記事で図書館の予約管理システムを構築しました。 データ取得まではできましたが、データ出力するところが実装できなかったので今回実装していこうと思います。 React使うか~とかも思ったのですが、Geminiと相談した結果Streamlitというライブラリを使うことにしました。 Streamlitとは グラフデータや表データなどを含むWebアプリを超簡単に構築できるライブラリです。 Streamlit • A faster way to build and share data apps もちろん自由度はReactでフロントエンドを作るよりも低くはなるのですが、大体の機能が揃っているのでとりあえずデータ出力したいだけであればこれで十分だと思います。 実装 ということで実装していきます。 今回は以下のデータクラスを表で出力します。 @dataclass class LoanStatusItem: deadline_at: dt.date borrower_name: str library_name: str book_title: str @dataclass class ReserveItem: status: Literal["reserved", "already"] borrower_name: str library_name: str book_title: str 必要なライブラリを追加します。 uv add streamlit pandas 実装はとりあえずダミーデータを使ってやりました。 def get_dummy_data(): # 貸出状況のデータ loans = [ LoanStatusItem(dt.date(2023, 10, 15), "佐藤", "中央図書館", "Python入門"), LoanStatusItem(dt.date(2023, 10, 20), "鈴木", "北図書館", "Streamlit実践"), LoanStatusItem(dt.date(2023, 10, 12), "佐藤", "中央図書館", "機械学習の基礎"), ] # 予約状況のデータ reserves = [ ReserveItem("reserved", "佐藤", "南図書館", "Web設計パターン"), ReserveItem("already", "田中", "中央図書館", "デザイン思考"), ReserveItem("reserved", "鈴木", "北図書館", "Docker活用"), ] current_time = dt.datetime.now().strftime('%H:%M:%S') return loans, reserves, current_time def main(): st.title("図書館 利用状況ダッシュボード") # --- 更新ボタンの配置 --- # col1, col2 を使うことで、タイトルやボタンの配置を調整できます col1, col2 = st.columns([3, 1]) with col1: st.write("最新の貸出・予約状況を表示します。") with col2: # ボタンが押されたらキャッシュをクリアして再実行 if st.button("最新情報を取得 🔄"): st.cache_data.clear() # キャッシュを削除 st.rerun() # スクリプトを再実行(画面更新) # データの取得 loans, reserves, fetched_time = get_dummy_data() # 更新時刻の表示 st.caption(f"データ取得時刻: {fetched_time}") # --- 1. 貸出状況の表示 --- st.subheader("📅 貸出状況 (Loan Status)") if loans: # dataclassのリストをDataFrameに変換 # dataclasses.asdictを使うと辞書に変換され、DataFrame化しやすくなります df_loans = pd.DataFrame([asdict(item) for item in loans]) # カラム名の見た目を整える(任意) df_loans = df_loans.rename(columns={ "deadline_at": "返却期限", "borrower_name": "利用者名", "library_name": "図書館", "book_title": "書名" }) # テーブル表示 (use_container_width=Trueで横幅いっぱいに表示) st.dataframe(df_loans, use_container_width=True) else: st.info("貸出中の本はありません。") st.markdown("---") # 区切り線 # --- 2. 予約状況の表示 --- st.subheader("🔖 予約状況 (Reserve Status)") if reserves: df_reserves = pd.DataFrame([asdict(item) for item in reserves]) # カラム名の整理 df_reserves = df_reserves.rename(columns={ "status": "状態", "borrower_name": "利用者名", "library_name": "図書館", "book_title": "書名" }) # 状態(reserved/already)に応じて色をつけたりも可能です st.dataframe(df_reserves, use_container_width=True) else: st.info("予約中の本はありません。") if __name__ == "__main__": main() これを実行します。 ...

2026年1月8日 · にあえん

Seleniumで図書館の予約管理システムを作った

こんにちは、ナナオです。 最近、いろんな図書館からいろんな本を借りることが多いのですが、書籍の予約管理を今はメモで行っており、ちょっとこれだと見づらいので一元管理できるシステムを作ることにしました。 ということで、早速実装していきましょう。 (Seleniumの詳細な説明は省略します、詳細はこちらから!) 仕様 とりあえず必要な仕様は以下の通りです。最初はシンプルにいきましょう。 WebUIを出力 書籍の予約を一覧で表示する 「名前」と「借りている図書館」を表示する とりあえずこれでいきましょう。 実装にはSeleniumと相性がよく、私がすぐ実装できるpythonを使用します。 実装 とりあえずローカルでseleniumを動作させられる環境を構築します。 まずは土台になるパッケージを作成します。 uvを使います。 uv init --package --project library-checker uv add selenium seleniumの動作環境構築はDockerでやるのが一番楽なので、以下のコマンドを実行します。 docker run -d -p 4444:4444 --rm --shm-size="2g" selenium/standalone-chrome:4.39.0-20251212 (実行イメージはこちらを参考にしました) これでとりあえず動作させる準備が整いました。 seleniumを動作させる基本実装は以下の通りです。 from selenium import webdriver def main(): # Chrome のオプションを設定する options = webdriver.ChromeOptions() options.add_argument('--headless') # Selenium Server に接続する driver = webdriver.Remote( command_executor='http://localhost:4444/wd/hub', options=options, ) # ブラウザを終了する driver.quit() if __name__ == "__main__": main() これで特にエラーなく動作すれば最初のステップは問題ないです。 ...

2026年1月7日 · にあえん