医療機関向けシステムのコンテナ運用において、院内電子カルテ(EMR)APIや外部AIエンジンとの連携を行うマイクロサービスをデプロイする場合、環境ごとの設定差分管理や証明書のライフサイクル制御、安全な認証情報の配布が極めて重要な課題となります。手動でマニフェストを書き換える手法や個別の仮想ホスト設定は、ノード拡張やマルチ環境展開時に人為的な操作ミスによる障害を引き起こすリスクが高まります。
本稿では、Helm v3を用いた医療系AIチャットボット(ai-chatbot)のパッケージングおよび抽象化手法、インメモリ型トークン共有アーキテクチャ、そしてArgoCDによるGitOps継続的デプロイメントの構成仕様について解説します。
システムアーキテクチャとトポロジ構造
対象のワークロードは、クラスタ内部のEMRエンドポイント(https://emr.myhospital.co.kr/api)および外部のOpenAI APIエンジンと通信します。本構成ではインフラ階層を明確に分離し、TLS終端を担うIngress、クラスタ内ルーティングを行うService(ClusterIP)、実体を構成するPodレプリカ群をHelmによって宣言的に制御します。
ai-chatbot/
├── Chart.yaml # チャートメタデータおよび semantic versioning 定義
├── values.yaml # デフォルト変数および実行時パラメータ
└── templates/ # Kubernetes マニフェストテンプレート
├── deployment.yaml # ポッドオーケストレーション制御
├── service.yaml # Layer 4 内部ネットワーク抽象化 (ClusterIP)
├── ingress.yaml # Layer 7 外部ルーティングおよび TLS 終端設定
└── configmap.yaml # 外部 API 設定およびシステムプロンプト定義
コアテンプレート設計仕様
1. メタデータ定義 (Chart.yaml)
Helm 3との互換性を保証するため apiVersion: v2 を指定し、アプリケーションのセマンティックバージョニングを設定します。
apiVersion: v2
name: ai-chatbot
description: 病院向けAIチャットボットHelmチャート
type: application
version: 0.1.0
appVersion: "1.0.0"
2. 環境変数およびリソース定義 (values.yaml)
稼働環境に応じたパラメータ変更を容易にするため、CPU/メモリ要求量、レプリカ数、Ingressホスト名を values.yaml に統一管理します。
replicaCount: 2
image:
repository: myregistry/ai-chatbot
tag: latest
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
ingress:
enabled: true
hostname: chatbot.myhospital.co.kr
tls: true
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "250m"
memory: "256Mi"
env:
EMR_API_URL: "https://emr.myhospital.co.kr/api"
CHATBOT_LANG: "ko"
3. ワークロード制御定義 (templates/deployment.yaml)
リソース制限や環境変数の動的挿入を行います。Helmテンプレート関数の nindent を正しく適用し、YAMLインデントの破損を防止します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-chatbot
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: ai-chatbot
template:
metadata:
labels:
app: ai-chatbot
spec:
containers:
- name: chatbot
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: 3000
env:
- name: EMR_API_URL
value: {{ .Values.env.EMR_API_URL | quote }}
- name: CHATBOT_LANG
value: {{ .Values.env.CHATBOT_LANG | quote }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
4. 内部サービスおよび Ingress 露出 (templates/service.yaml, templates/ingress.yaml)
service.yaml により80番ポートからコンテナの3000番ポートへトラフィックを転送し、ingress.yaml によりNGINX Ingress Controller経由のSSLリダイレクトおよびTLS終端を適用します。
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}-chatbot
spec:
type: {{ .Values.service.type }}
selector:
app: ai-chatbot
ports:
- protocol: TCP
port: {{ .Values.service.port }}
targetPort: 3000
```yaml
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ .Release.Name }}-chatbot
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
rules:
- host: {{ .Values.ingress.hostname }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ .Release.Name }}-chatbot
port:
number: {{ .Values.service.port }}
{{- if .Values.ingress.tls }}
tls:
- hosts:
- {{ .Values.ingress.hostname }}
secretName: chatbot-tls
{{- end }}
{{- end }}
5. OpenAI 設定用 ConfigMap (templates/configmap.yaml)
モデル識別子やプロンプトパラメータをアプリケーション本体から切り離して外部化します。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-chatbot-config
labels:
app: ai-chatbot
data:
OPENAI_MODEL: "gpt-4o"
OPENAI_MAX_TOKENS: "2048"
OPENAI_TEMPERATURE: "0.2"
SYSTEM_PROMPT: |
You are an AI assistant designed for hospital settings.
You assist medical personnel and patients by answering queries based on the hospital's EMR dataset.
Always operate under medical protocol standards.
EMR 認証トークン統合パターン
医療データ(PHI)の流出を防止するため、EMRアクセストークンは永続ストレージではなくメモリ上にのみ保持する設計を採用します。
- Sidecar/InitContainer パターン: 認証サイドカーがEMR認証サーバー(
https://emr.myhospital.co.kr)から短寿命JWTトークンを取得します。 - In-Memory ボリューム (
tmpfs): 取得したトークンはmedium: Memoryで構成されたemptyDirボリューム(/var/run/secrets/emr)に書き込まれ、メインのチャットボットコンテナから参照されます。 - 動的トークン更新: チャットボットアプリケーション層のOAuth2クライアントモジュールが定期的にトークンの有効期限を検証し、Podを再起動することなくメモリ上のJWTを透過的に更新します。
GitOps パイプライン構成 (argocd-application.yaml)
ArgoCDを用いてGitリポジトリの状態とクラスタの実体を自動同期します。
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: ai-chatbot-prod
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: 'https://github.com/myhospital-org/helm-charts.git'
targetRevision: HEAD
path: ai-chatbot
helm:
valueFiles:
- values.yaml
destination:
server: 'https://kubernetes.default.svc'
namespace: ai-services
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
トラブルシューティング 🛠️
1. nindent 関数適用不備による YAML パースエラー
- 現象:
helm template実行時にerror converting YAML to JSON: yaml: line X: did not find expected keyが発生します。 - 原因:
deployment.yaml内のresources:ブロック直下でnindentのインデント数が合致していない場合、構文エラーが発生します。 - 対策:
{{- toYaml .Values.resources | nindent 12 }}のように、resourcesキーの配下に入る正確なスペース数(12スペース)を正しく指定します。
2. Ingress の TLS Secret 不整合による 502/SSL エラー
- 現象: 外部からHTTPSアクセス時にデフォルトのKubernetes Ingress Fake Certificateが返却され、接続が拒否されます。
- 原因:
values.yamlで定義したchatbot-tlsSecretが対象のネームスペースに存在しない、またはIngressのhost名と証明書のSAN(Subject Alternative Name)が一致していません。 - 対策: 証明書管理コンポーネント(cert-manager等)を用いて、ターゲットネームスペース(
ai-services)内に正しくchatbot-tlsが生成されているかを検証します。
3. メモリバックド emptyDir の書き込み権限エラー
- 現象: サイドカーコンテナからトークンファイル書き込み時に
Permission deniedが発生し、PodがCrashLoopBackOffに陥ります。 - 原因: セキュリティコンテキストで非rootユーザー実行を定義している際、マウントされた
emptyDirボリュームのオーナー権限が一致していません。 - 対策:
securityContextのfsGroup設定をPod仕様に追加し、書き込み権限を持つGIDを明示的に割り当てます。
動作検証および検証ログ
デプロイメント完了後、以下の検証用ターミナルコマンドを実行してオブジェクトの正常性を確認します。
$ helm status chatbot -n ai-services
NAME: chatbot
LAST DEPLOYED: Sun Sep 27 10:15:22 2026
NAMESPACE: ai-services
STATUS: deployed
REVISION: 1
TEST SUITE: None
$ kubectl get pods -n ai-services -l app=ai-chatbot -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
chatbot-ai-chatbot-67f9b87c-x92zk 1/1 Running 0 2m 10.244.1.45 k8s-worker-01 <none> <none>
chatbot-ai-chatbot-67f9b87c-z4l8p 1/1 Running 0 2m 10.244.2.89 k8s-worker-02 <none> <none>
$ kubectl get ingress -n ai-services
NAME CLASS HOSTS ADDRESS PORTS AGE
chatbot-ai-chatbot nginx chatbot.myhospital.co.kr 192.168.1.100 80, 443 2m
$ curl -I -sS https://chatbot.myhospital.co.kr/
HTTP/2 200
server: nginx/1.25.3
date: Sun, 27 Sep 2026 10:17:45 GMT
content-type: text/html; charset=utf-8
strict-transport-security: max-age=15724800; includeSubDomains
設定上の留意事項 💡
- リソース制限の調整: EMR応答の解析処理によりスパイクアクセスが発生する場合、
values.yamlのresources.limits.cpuをノードのコア数に応じて適切にチューニングしてください。 - プロンプト情報の管理: ConfigMap内のシステムプロンプトの更新はPodの自動再起動を誘発しないため、設定反映にはArgoCDによるローリングアップデートまたはPodの再作成を伴う運用を推奨します。
- ネットワークポリシー: 医療データを取り扱う性質上、
ai-servicesネームスペースに対してEMR認証エンドポイントおよびIngress以外の外部アウトバウンド通信を制限するNetworkPolicyの併用を推奨します。