Kubernetesクラスタへのtt-rssのデプロイ方法
Tiny Tiny RSS(tt-rss)は自宅サーバーで運用できるオープンソースのRSSリーダーである。複数デバイスでの同期、カスタマイズ可能なインターフェース、プラグインによる拡張性など、多くの優れた機能を持っている。
私がRSSリーダーを利用する理由は主に二つある:
- 情報の選択的取得: 現代の情報過多環境において、自分が選んだ情報源からのみ情報を受け取ることで、頭が疲れない。
- 誘惑の排除: 例えば、YouTubeのチャンネルをRSSで購読することで、おすすめの動画を観ずに済む。誘惑と戦う必要がなくなる。
tt-rssを選んだ理由は、サービス終了のリスクがなく、自宅サーバーで運用できるため。自己ホスティング可能なRSSリーダーとしてFreshRSSなども選択肢に挙がるが、tt-rssは拡張性において優れている。
Helmチャート(Kubernetesパッケージ管理ツール)を使ったtt-rssのデプロイ方法は見つかるものの、Kubernetesマニフェストを一から記述する方法についての情報はまだ少ない。そのため、以下の流れでtt-rssのK8sクラスタへのデプロイ方法を解説する:
- システム構成と環境の説明
- MySQLデータベースのデプロイ
- tt-rssアプリケーションのデプロイ
- Nginxリバースプロキシのデプロイ
本記事では、Raspberry PiのARM64アーキテクチャに対応したコンテナイメージを使用しているが、イメージを変更するだけで他のアーキテクチャでも適用可能である。
構成ファイルは別々に作成することも、一つにまとめることもできる。一括設定したい場合は、記事末尾のおまけの節を参照。この記事では、必要最低限の構成を紹介するため、自身の環境に合わせて自由にカスタマイズしてください。
事前知識:必要なKubernetesリソース
デプロイに使用する主要なKubernetesリソースは以下の通りである:
- Namespace: リソースを論理的にグループ化し、tt-rssとNginxを分離管理
- Deployment: アプリケーションのPod管理とスケーリング
- Service: Podへのアクセスポイントを提供し、安定した通信を確保
- PersistentVolumeClaim: データベースデータの永続化
- Secret: パスワードなどの機密情報を安全に管理
システム構成
今回構築するシステムは以下のコンポーネントで構成される:
- Nginxリバースプロキシ: 外部からのアクセスを受け付け、tt-rssへ転送
- tt-rssアプリケーション: RSSリーダー本体
- MySQLデータベース: tt-rssのデータを保存
外部からのアクセスがNginxを経由してtt-rssに到達し、tt-rssはMySQLにデータを保存するという流れ。また、各コンポーネントは別々のPodとして実行され、Service経由で接続される。これにより個別の更新やスケーリングが可能になる。
MySQLのデプロイ
名前空間の作成
最初に、tt-rss関連のリソースを論理的に分離するための名前空間を作成する。これにより、リソースの管理がしやすくなり、他のアプリケーションとの衝突を避けられる。
# ttrss-namespace.yaml
# tt-rss関連のリソースを論理的にグループ化するための名前空間
apiVersion: v1
kind: Namespace
metadata:
name: ttrss # この名前空間内にtt-rssとMySQLのリソースを配置
データベース接続用シークレット
データベースのパスワードはSecretとして管理する。これにより、マニフェストファイルに平文でパスワードを記載せずに済み、セキュリティが向上する。
# MySQLのルートパスワードとtt-rssユーザー用パスワードをSecretとして作成
kubectl create secret generic mysql-secret \
--from-literal=mysql_root_pass=rootpassword \
--from-literal=mysql_ttrss_pass=ttrsspassword -n ttrss
MySQLデータベースのPVC
データベースのデータを永続化するために、PersistentVolumeClaimを作成する。これにより、Podが再起動してもデータが失われない。
# mysql-pvc.yaml
# MySQLのデータを永続化するためのPersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
namespace: ttrss # ttrss名前空間に配置
name: mysql-pvc # このPVCはMySQLデプロイメントから参照される
spec:
accessModes:
- ReadWriteOnce # 単一ノードからの読み書きアクセスを許可
resources:
requests:
storage: 1Gi # 1GBのストレージを要求(必要に応じて調整可能)
MySQLデプロイメント
MySQLデータベースをKubernetesクラスタにデプロイする。このデプロイメントでは、ARM64対応のMySQLイメージを使用し、必要な環境変数とボリュームマウントを設定する。
# mysql-deployment.yaml
# MySQLデータベースをデプロイするためのマニフェスト
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: ttrss # ttrss名前空間に配置
name: mysql # デプロイメント名
spec:
replicas: 1 # MySQLは単一インスタンスで実行(レプリケーション構成ではない)
selector:
matchLabels:
app: mysql # このラベルを持つPodを管理対象とする
template:
metadata:
labels:
app: mysql # Podにラベルを付与
spec:
containers:
- name: mysql
image: arm64v8/mysql:8.0 # ARM64アーキテクチャ用のMySQLイメージ
env:
# MySQLの設定を環境変数で指定
- name: MYSQL_ROOT_PASSWORD # ルートパスワード(Secretから取得)
valueFrom:
secretKeyRef:
name: mysql-secret
key: mysql_root_pass
- name: MYSQL_DATABASE
value: ttrss # tt-rss用のデータベース名
- name: MYSQL_USER
value: ttrss # tt-rss用のデータベースユーザー
- name: MYSQL_PASSWORD # ユーザーパスワード(Secretから取得)
valueFrom:
secretKeyRef:
name: mysql-secret
key: mysql_ttrss_pass
ports:
- containerPort: 3306 # MySQLの標準ポート
volumeMounts:
- name: mysql-storage # データの永続化のためのボリューム
mountPath: /var/lib/mysql # MySQLのデータディレクトリ
volumes:
- name: mysql-storage
persistentVolumeClaim:
claimName: mysql-pvc # 先に作成したPVCを使用
MySQLサービス
MySQLにアクセスするためのサービスを作成する。このサービスによりtt-rssアプリケーションからデータベースへ安定してアクセスできるようになる。
# mysql-service.yaml
# MySQLにアクセスするためのサービス定義
apiVersion: v1
kind: Service
metadata:
namespace: ttrss # ttrss名前空間に配置
name: mysql # サービス名(このDNS名でクラスタ内からアクセス可能)
spec:
selector:
app: mysql # mysql Podをターゲットとする
ports:
- port: 3306 # 標準のMySQLポート
type: ClusterIP # クラスタ内部でのみアクセス可能
tt-rssのデプロイ
tt-rssデプロイメント
tt-rssアプリケーション本体をデプロイする。このデプロイメントでは、tt-rssコンテナと、データベース接続に必要な環境変数を設定する。
# ttrss-deployment.yaml
# tt-rssアプリケーションをデプロイするためのマニフェスト
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: ttrss # ttrss名前空間に配置
name: ttrss # デプロイメント名
spec:
replicas: 1 # 単一インスタンスでデプロイ
selector:
matchLabels:
app: ttrss # このラベルを持つPodを管理対象とする
template:
metadata:
labels:
app: ttrss # Podにラベルを付与
spec:
containers:
- name: ttrss
image: nventiveux/ttrss # tt-rssのコンテナイメージ
env:
# データベース接続情報を環境変数で設定
- name: TTRSS_DB_HOST
value: mysql # MySQLサービス名
- name: TTRSS_DB_PORT
value: "3306" # MySQLポート
- name: TTRSS_DB_NAME
value: ttrss # データベース名
- name: TTRSS_DB_USER
value: ttrss # データベースユーザー
- name: TTRSS_DB_PASS # データベースパスワード(Secretから取得)
valueFrom:
secretKeyRef:
name: mysql-secret
key: mysql_ttrss_pass
- name: TTRSS_DB_TYPE
value: mysql # データベースタイプ
- name: TTRSS_SELF_URL_PATH
value: "http://IP_Address:30080/" # tt-rssの外部アクセスURL(自環境に合わせて変更)
ports:
- containerPort: 80 # tt-rssのWebサーバーポート
tt-rssサービス
tt-rssにアクセスするためのサービスを作成する。このサービスによりNginxからtt-rssへの通信が可能になる。
# ttrss-service.yaml
# tt-rssアプリケーションにアクセスするためのサービス定義
apiVersion: v1
kind: Service
metadata:
namespace: ttrss # ttrss名前空間に配置
name: ttrss # サービス名(このDNS名でクラスタ内からアクセス可能)
spec:
selector:
app: ttrss # ttrss Podをターゲットとする
ports:
- name: http
port: 80 # サービスポート
targetPort: 80 # コンテナポート
protocol: TCP
type: ClusterIP # クラスタ内部でのみアクセス可能
Nginxのデプロイ
名前空間の作成
Nginxのリソースを分離管理するための専用の名前空間を作成する。これにより、tt-rssとは別の管理ができるようになる。
# nginx-namespace.yaml
# Nginxリソースを分離管理するための名前空間
apiVersion: v1
kind: Namespace
metadata:
name: nginx # Nginx関連のリソース用の名前空間
labels:
app: nginx
role: reverse-proxy # リバースプロキシとしての役割を明示
Nginx設定用ConfigMap
Nginxの設定をConfigMapとして管理する。これにより、Nginx設定を柔軟に更新でき、デプロイメントと設定を分離できる。
# nginx-configmap.yaml
# Nginxの設定をConfigMapとして管理
apiVersion: v1
kind: ConfigMap
metadata:
namespace: nginx # nginx名前空間に配置
name: nginx-config # ConfigMap名
data:
default.conf: |
server {
listen 80;
server_name localhost;
# tt-rssへのリバースプロキシ設定
location / {
# 内部DNSを使用してtt-rssサービスにリクエストを転送
proxy_pass http://ttrss.ttrss.svc.cluster.local:80/;
# クライアント情報を適切にtt-rssに伝えるためのヘッダー設定
proxy_set_header Host $host:30080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Nginxデプロイメント
Nginxをデプロイする。このデプロイメントでは、Nginxコンテナを実行し、先ほど作成したConfigMapを設定ファイルとしてマウントする。
# nginx-deployment.yaml
# Nginxリバースプロキシをデプロイするためのマニフェスト
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: nginx # nginx名前空間に配置
name: nginx # デプロイメント名
labels:
app: nginx
spec:
replicas: 1 # 単一インスタンスでデプロイ(高可用性が必要なら増やすことも可能)
selector:
matchLabels:
app: nginx # このラベルを持つPodを管理対象とする
template:
metadata:
labels:
app: nginx # Podにラベルを付与
spec:
volumes:
- name: nginx-config # 設定ファイル用のボリューム
configMap:
name: nginx-config # 先に作成したConfigMapを参照
containers:
- name: nginx
image: nginx:latest # Nginxの公式イメージを使用
ports:
- containerPort: 80 # Nginxの標準HTTPポート
volumeMounts:
- name: nginx-config # ConfigMapをマウント
mountPath: /etc/nginx/conf.d/ # Nginxの設定ディレクトリ
Nginxサービス
Nginxサービスを作成してノードポートで公開する。これにより、クラスタ外部からtt-rssにアクセスできるようになる。
# nginx-service.yaml
# Nginxサービスを外部公開するためのマニフェスト
apiVersion: v1
kind: Service
metadata:
namespace: nginx # nginx名前空間に配置
name: nginx-service # サービス名
spec:
selector:
app: nginx # nginx Podをターゲットとする
ports:
- port: 80 # サービスポート
targetPort: 80 # コンテナポート
nodePort: 30080 # ノードの30080ポートで外部公開
type: NodePort # ノードポートタイプのサービスとして公開
tt-rssへのアクセス
デプロイが完了したら、以下のURLでtt-rssにアクセスできる:
http://<ノードIP>:30080/
初回アクセス時に、デフォルトのユーザー名「admin」とパスワード「password」でログインできる。
正常に動作しない場合は、kubectl describe pod
や kubectl logs
コマンドで詳細を確認してください。
おまけ:一括設定
Nginx manifest
# nginx-all.yaml
# Nginxに関する全てのリソースを一括で定義するマニフェスト
# Nginx用の名前空間
apiVersion: v1
kind: Namespace
metadata:
name: nginx
labels:
app: nginx
role: reverse-proxy
---
# Nginx設定用ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
namespace: nginx
name: nginx-config
data:
default.conf: |
server {
listen 80;
server_name localhost;
# tt-rssへのリバースプロキシ設定
location / {
# 内部DNSを使用してtt-rssサービスにリクエストを転送
proxy_pass http://ttrss.ttrss.svc.cluster.local:80/;
# クライアント情報を適切にtt-rssに伝えるためのヘッダー設定
proxy_set_header Host $host:30080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
---
# Nginxデプロイメント
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: nginx
name: nginx
labels:
app: nginx
spec:
replicas: 1 # 高可用性が必要なら増やすことも可能
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
volumes:
- name: nginx-config
configMap:
name: nginx-config
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d/
---
# Nginxサービス(NodePortで外部公開)
apiVersion: v1
kind: Service
metadata:
namespace: nginx
name: nginx-service
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
nodePort: 30080
type: NodePort
tt-rss manifest
# ttrss-all.yaml
# tt-rssとMySQLに関する全てのリソースを一括で定義するマニフェスト
# tt-rss用の名前空間
apiVersion: v1
kind: Namespace
metadata:
name: ttrss
---
# MySQLデータ用のPVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
namespace: ttrss
name: mysql-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
# MySQLデプロイメント
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: ttrss
name: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: arm64v8/mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: mysql_root_pass
- name: MYSQL_DATABASE
value: ttrss
- name: MYSQL_USER
value: ttrss
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: mysql_ttrss_pass
ports:
- containerPort: 3306
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-storage
persistentVolumeClaim:
claimName: mysql-pvc
---
# MySQLサービス
apiVersion: v1
kind: Service
metadata:
namespace: ttrss
name: mysql
spec:
selector:
app: mysql
ports:
- port: 3306
type: ClusterIP
---
# tt-rssデプロイメント
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: ttrss
name: ttrss
spec:
replicas: 1
selector:
matchLabels:
app: ttrss
template:
metadata:
labels:
app: ttrss
spec:
containers:
- name: ttrss
image: nventiveux/ttrss
env:
- name: TTRSS_DB_HOST
value: mysql
- name: TTRSS_DB_PORT
value: "3306"
- name: TTRSS_DB_NAME
value: ttrss
- name: TTRSS_DB_USER
value: ttrss
- name: TTRSS_DB_PASS
valueFrom:
secretKeyRef:
name: mysql-secret
key: mysql_ttrss_pass
- name: TTRSS_DB_TYPE
value: mysql
- name: TTRSS_SELF_URL_PATH
value: "http://IP_Address:30080/"
ports:
- containerPort: 80
---
# tt-rssサービス
apiVersion: v1
kind: Service
metadata:
namespace: ttrss
name: ttrss
spec:
selector:
app: ttrss
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
type: ClusterIP