Kubernetes CronJobとは?設定方法と実行例
はじめに
現代のアプリケーション運用において、定期的なタスクの実行は不可欠です。データベースのバックアップ、ログファイルのクリーンアップ、レポートの生成、データの集計処理など、特定の時間に自動的に実行されるべきバッチ処理は多岐にわたります。従来のシステムでは、これらのタスクは各サーバーにインストールされた cron
デーモンなどを使って管理されることが一般的でした。
しかし、コンテナ化されたマイクロサービスアーキテクチャや、Kubernetesのような分散システム環境では、従来のサーバーごとの cron
管理には限界があります。特定のサーバーが停止した場合にタスクが実行されない、タスクの実行状態を一元的に管理できない、コンテナ環境に依存しない柔軟なスケジューリングが難しい、といった課題が生じます。
Kubernetesは、コンテナ化されたワークロードを自動的にデプロイ、スケーリング、管理するためのオープンソースプラットフォームです。Kubernetesは様々な種類のワークロードをサポートしており、その中に定期的なタスクを実行するための仕組みとして CronJob があります。CronJobは、Kubernetesクラスター上で指定されたスケジュールに従ってJobオブジェクトを自動的に作成するコントローラーです。これにより、Kubernetesの持つ高い可用性、スケーラビリティ、宣言的な管理といった利点を活かしつつ、バッチ処理を効率的に実行できます。
この記事では、KubernetesのCronJobについて、その基本的な概念から詳細な設定方法、具体的な実行例、さらには高度な設定やトラブルシューティングの方法まで、約5000語にわたって徹底的に解説します。この記事を読むことで、Kubernetesクラスター上での定期実行タスクの管理方法を深く理解し、実践できるようになるでしょう。
CronJobの基本
CronJobとは
Kubernetesの CronJob は、指定されたスケジュール(cronフォーマット)に従って Job リソースを繰り返し実行するためのコントローラーです。Jobは、1つ以上のPodを作成し、指定されたタスクを完了するまで実行するKubernetesリソースです。タスクが成功裏に完了すると、Jobは完了とマークされます。CronJobは、このJobを定期的に、あるいは一回限り未来の特定の時間に実行させる目的で使用されます。
簡単に言えば、CronJobは従来のLinuxサーバーなどで使われる cron
コマンドのKubernetes版と考えることができます。しかし、単に時間を指定してコマンドを実行するだけでなく、Kubernetesクラスターの耐障害性、スケーラビリティ、リソース管理の機能を利用できる点が大きく異なります。
CronJobが適しているタスク
CronJobは、以下のような定期的なバッチ処理に特に適しています。
- データベースのバックアップ: 毎日または毎週、データベースのダンプを取得し、外部ストレージに保存するタスク。
- ログファイルのクリーンアップ/ローテーション: 古いログファイルを削除したり、アーカイブしたりするタスク。
- レポート生成: 定期的にデータを集計し、レポートファイルを生成したり、メールで送信したりするタスク。
- データ同期/ETL処理: 外部システムからデータを取得し、変換してデータベースにロードするタスク。
- ヘルスチェック/監視: 特定のサービスやエンドポイントに定期的にアクセスし、応答を確認するタスク。
- キューからのバッチ処理: メッセージキューに溜まったジョブを一定間隔でまとめて処理するタスク。
これらのタスクは、特定の時間に実行される必要があり、通常は一度実行されれば完了となる「バッチ」的な性質を持ちます。CronJobは、このようなタスクのスケジューリングと実行管理をKubernetes上で行うための標準的な方法を提供します。
CronJobのコンポーネント
CronJobを理解するためには、それが内部でどのように機能するかを知ることが重要です。CronJobは主に以下の要素から構成されます。
- CronJobオブジェクト自身: スケジュール情報や、実行されるJobのテンプレート、履歴管理設定などを保持するKubernetesリソースです。
- Jobテンプレート (
jobTemplate
): CronJobがスケジュール時刻に達した際に作成するJobオブジェクトの定義を含みます。このテンプレートは、Jobが実行するPodの仕様(コンテナイメージ、コマンド、環境変数など)を定義するPodテンプレート (template
) を含んでいます。 - Jobオブジェクト: CronJobによってスケジュールに従って実際に作成されるリソースです。Jobは、Podテンプレートに基づいて1つ以上のPodを起動し、タスクの完了を管理します。タスクが成功または失敗すると、Jobは完了状態となります。
- Pod: Jobによって作成される実際の実行単位です。コンテナ内で指定されたコマンドやスクリプトを実行します。タスクが完了すると、Podも終了します。
つまり、CronJobは「いつ、どのようなJobを実行するか」を定義し、Kubernetesコントローラーマネージャー内のCronJobコントローラーが、その定義に従って適切なタイミングでJobオブジェクトを作成します。Jobオブジェクトは、さらにそのJobテンプレート内のPodテンプレートに従ってPodを作成し、タスクを実行します。
CronJobの設定(マニフェストファイルの詳細)
Kubernetesのリソースは通常、YAML形式のマニフェストファイルとして定義されます。CronJobも同様に、このマニフェストファイルを作成してクラスターに適用することで設定を行います。以下に、CronJobマニフェストの主要なフィールドとその詳細な説明を示します。
yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: my-cronjob
namespace: default # 任意
spec:
schedule: "*/5 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox:1.36.1 # 最新の安定版を指定
command: ["/bin/sh", "-c", "date; echo Hello from the Kubernetes cluster"]
restartPolicy: OnFailure
startingDeadlineSeconds: 60
concurrencyPolicy: Allow
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
suspend: false
timeZone: "UTC" # または "Asia/Tokyo" など
各フィールドについて詳しく見ていきましょう。
apiVersion
, kind
, metadata
apiVersion: batch/v1
: CronJobリソースはbatch/v1
APIグループに属します。kind: CronJob
: このリソースがCronJobであることを示します。metadata
: リソースのメタデータです。name
: CronJobの名前を指定します。クラスター内で一意である必要があります。namespace
: CronJobを作成する名前空間を指定します(省略可能、デフォルトはdefault
)。labels
,annotations
: リソースを識別・管理するためのラベルや注釈を設定できます。
spec
CronJobの実行に関する仕様を定義します。
-
schedule
(必須):- タスクを実行するスケジュールを cronフォーマット で指定します。これは非常に重要なフィールドです。
- 一般的なcronフォーマットは以下の5つのフィールドで構成されます。
“`
| | | | |
| | | | —– 曜日 (0-6, 日曜日=0または7)
| | | ——- 月 (1-12)
| | ——— 日 (1-31)
| ———– 時 (0-23)
————- 分 (0-59)
“` -
各フィールドには以下の値や特殊文字を使用できます。
*
: すべての値に一致します。例えば、分のフィールドが*
なら毎分実行されます。,
: 値のリストを指定します。例えば、分のフィールドが0,15,30,45
なら毎時0分、15分、30分、45分に実行されます。-
: 値の範囲を指定します。例えば、時のフィールドが9-17
なら9時から17時まで毎時実行されます。/
: ステップ値を指定します。例えば、分のフィールドが*/5
なら5分ごとに実行されます。?
: 日付と曜日のフィールドで排他的に使用されます。どちらかのフィールドに*
ではなく?
を指定することで、「そのフィールドは任意の値でよい」という意味になります。通常は日付または曜日のどちらかを固定する場合にもう一方に?
を指定します。例えば、毎月特定の日に実行したい場合は曜日に?
を、特定の曜日に実行したい場合は日付に?
を指定します。L
: 日付フィールドでは月の最終日、曜日フィールドでは週の最終日(通常は土曜日)を表します。例えば、日付フィールドがL
なら毎月最終日に実行されます。曜日フィールドが5L
ならその月の最終金曜日に実行されます。W
: 日付フィールドで指定された日付に最も近い平日(月-金)を表します。例えば、日付フィールドが15W
なら、15日が土曜日なら14日(金)、日曜日なら16日(月)に実行されます。平日の場合はその日に実行されます。#
: 曜日フィールドで指定された月の第N番目の曜日を表します。例えば、曜日フィールドが5#3
なら毎月第3金曜日に実行されます。
-
Cron式の例:
*/5 * * * *
: 5分ごとに実行0 * * * *
: 毎時0分(正時)に実行0 0 * * *
: 毎日午前0時0分に実行0 0 1 * *
: 毎月1日午前0時0分に実行0 0 * * 1
: 毎週月曜日午前0時0分に実行 (0または7が日曜日なので、1は月曜日)30 21 * * *
: 毎日21時30分に実行0 6,18 * * *
: 毎日午前6時と午後6時0分に実行0 0 * * 1-5
: 月曜日から金曜日まで毎日午前0時0分に実行0 0 1,15 * *
: 毎月1日と15日午前0時0分に実行0 0 L * *
: 毎月最終日午前0時0分に実行0 0 * * 5L
: 毎月最終金曜日午前0時0分に実行0 0 15W * *
: 毎月15日に最も近い平日午前0時0分に実行0 0 * * 3#2
: 毎月第2水曜日午前0時0分に実行@hourly
: 毎時1回(通常は0分)@daily
: 毎日1回(通常は0時0分)@weekly
: 毎週1回(通常は日曜日0時0分)@monthly
: 毎月1回(通常は1日0時0分)@yearly
/@annually
: 毎年1回(通常は1月1日0時0分)@reboot
: Kubernetes CronJobではサポートされていません。
- CronJobコントローラーは、指定されたスケジュールに従って 各スケジュール時刻に対して最大1つのJobを作成しようとします。何らかの理由でJobの作成が遅延した場合(例えば、コントローラーがダウンしていたなど)、その遅延期間中に複数のスケジュール時刻が過ぎたとしても、通常は最新のスケジュール時刻に対してのみJobを作成します。この挙動は
startingDeadlineSeconds
とconcurrencyPolicy
の設定によって影響を受けます。
-
jobTemplate
(必須):- CronJobがスケジュールに従って実行するJobオブジェクトのテンプレートです。このテンプレートの仕様に基づいて、CronJobコントローラーがJobリソースを動的に作成します。
- このフィールドは、
spec
フィールドを持つJob定義そのものです。 -
spec
内には、Jobの実行に関する設定が含まれます。特に重要なのはtemplate
フィールドです。template
(必須):- Jobが作成するPodオブジェクトのテンプレートです。このテンプレートの仕様に基づいて、JobコントローラーがPodを起動します。
- このフィールドは、
spec
フィールドを持つPod定義そのものです。 spec
内には、Podの実行に関する設定が含まれます。containers
(必須):- Pod内で実行されるコンテナのリストです。CronJobで実行する実際のタスクの定義はここで行います。
name
: コンテナの名前。image
: コンテナイメージの名前(例:ubuntu:latest
,busybox
, カスタムイメージ)。command
,args
: コンテナ起動時に実行されるコマンドとその引数。command
はDockerfileのENTRYPOINT
に相当し、args
はCMD
に相当します。DockerfileでENTRYPOINT
が指定されている場合はargs
のみ指定すれば引数として渡され、ENTRYPOINT
が指定されていない場合はcommand
を指定することで実行コマンドを上書きできます。env
: 環境変数。コンテナ内で利用する設定値などを渡すのに便利です。resources
: コンテナが必要とするCPUやメモリのリソース要求 (requests
) と上限 (limits
) を定義します。これにより、クラスターのリソースを効率的に利用し、他のワークロードへの影響を抑えることができます。volumeMounts
: ボリュームをコンテナ内のどのパスにマウントするかを定義します。
restartPolicy
: Podの再起動ポリシー。Jobが作成するPodの場合、タスクの完了を想定しているため、OnFailure
(コンテナが失敗した場合のみ再起動) またはNever
(再起動しない) が推奨されます。Always
はCronJob/Jobでは使用できません。volumes
: Podで使用するボリュームを定義します。ConfigMap、Secret、PersistentVolumeClaimなどをマウントできます。serviceAccountName
: Podが使用するService Accountを指定します。これにより、PodがKubernetes APIと連携する際の権限を制御できます(RBACと連携)。nodeSelector
,affinity
,tolerations
: 特定のノードでPodを実行するための制約を設定します。
-
Jobテンプレート (
jobTemplate.spec
) に含まれるその他の重要なフィールド:backoffLimit
: Podが失敗と見なされる前に許容されるリトライ回数。コンテナの終了コードが0以外の場合にPodは失敗と見なされ、指定された回数まで再起動が試みられます。全てのPodが指定回数失敗すると、Job全体が失敗とマークされます。デフォルトは6。activeDeadlineSeconds
: Jobがアクティブでいられる最大秒数。この時間内にJobが完了しなかった場合、Jobはキャンセルされ、失敗とマークされます。実行時間の長いタスクや、ハングアップしたタスクを自動的に終了させるのに役立ちます。ttlSecondsAfterFinished
: Jobが完了 (成功または失敗) とマークされた後に、システムが自動的にJobをクリーンアップするまでの秒数。これにより、完了したJobリソースがetcdに蓄積されてしまうのを防ぐことができます。Kubernetes 1.21+ で推奨される履歴管理方法です。
-
startingDeadlineSeconds
:- スケジュールされた実行時刻からJobが実際に開始されるまでの許容最大遅延秒数。
- もし、スケジュール時刻からこの秒数を超えてもJobが開始できない場合(例えば、前のJobがまだ実行中である、クラスターリソースが不足している、コントローラーがダウンしているなど)、その回のJob実行は スキップ されます。
- この設定により、大幅に遅延したJobが意図せず後で実行されるのを防ぐことができます。設定しない場合、遅延しても可能な限り早く実行しようとします。
- 通常、タスクの性質に応じて適切な値を設定します。例えば、厳密な時間管理が必要なら小さい値を、多少遅れても良いなら大きい値を設定します。
-
concurrencyPolicy
:- 前のスケジュール時刻のJobがまだ完了していない場合に、新しいJobをどう扱うかを制御します。
- 以下の3つのポリシーがあります。
Allow
(デフォルト): 同時実行を許可します。前のJobが実行中でも、新しいJobをスケジュール通りに開始します。Forbid
: 同時実行を禁止します。前のJobがまだ完了していない場合、新しいJobの実行は スキップ されます。厳密に1つのインスタンスだけが実行されていることを保証したい場合に有用です(例: 複数のバックアッププロセスが同時に走るのを避けたい場合)。Replace
: 前のJobがまだ実行中の場合、それを キャンセル して新しいJobを開始します。これは、常に最新のスケジュールでの実行を優先したい場合に適しています(ただし、実行中のJobを強制終了させるリスクを伴います)。
- どのポリシーを選択するかは、タスクの冪等性やリソースの競合可能性などを考慮して慎重に決定する必要があります。
-
suspend
:- ブール値 (
true
またはfalse
)。CronJobのスケジュール実行を一時停止するかどうかを指定します。 true
に設定すると、CronJobコントローラーは新しいJobを作成しなくなります。既存の実行中のJobは影響を受けません。false
に戻すと、再度スケジュールに従ってJobの作成が再開されます。一時停止中にスキップされたスケジュールについては、startingDeadlineSeconds
の設定に従って処理されるかスキップされます。- メンテナンスやデバッグ中に、一時的に特定のCronJobの実行を止めたい場合に便利です。
- ブール値 (
-
successfulJobsHistoryLimit
:- 成功した Jobの履歴をいくつ保持するかを指定します。古いものから削除されます。
- デフォルトは3。0に設定すると、成功したJobは完了後に即座に削除されます。
- デバッグや監査のために履歴を残したい場合に数を増やしますが、etcdのストレージを圧迫しないように適切な数に制限することが重要です。
-
failedJobsHistoryLimit
:- 失敗した Jobの履歴をいくつ保持するかを指定します。古いものから削除されます。
- デフォルトは1。0に設定すると、失敗したJobは完了後に即座に削除されます。
- 失敗の原因究明のために履歴を残すことが多いため、成功履歴より多めに保持することが一般的です。ただし、etcdストレージの制限は考慮が必要です。
-
timeZone
:- スケジュール (
schedule
) を評価する際に使用するタイムゾーンを指定します。 - IANA Time Zone Database名を指定します(例:
"UTC"
,"Asia/Tokyo"
,"America/New_York"
)。 - 指定しない場合、Kubernetesコントローラーマネージャーが動作しているノードのローカルタイムゾーンが使用される 可能性があります が、これは推奨されません。ノード間でタイムゾーンが異なる場合や、クラウドプロバイダーのデフォルトタイムゾーンに依存するのは予期しない挙動を招く可能性があるため、明示的にタイムゾーンを指定することが強く推奨されます。通常は
"UTC"
を使用するか、必要に応じて地域のタイムゾーンを指定します。
- スケジュール (
これらのフィールドを組み合わせて、タスクの要件に応じたCronJobを柔軟に設定できます。
CronJobの作成と管理
CronJobを設定するマニフェストファイル(例: my-cronjob.yaml
)を作成したら、kubectl
コマンドを使用してKubernetesクラスターに適用します。
作成
マニフェストファイルを使ってCronJobを作成します。
bash
kubectl apply -f my-cronjob.yaml
成功すると、CronJobが作成されたことを示すメッセージが表示されます。
cronjob.batch/my-cronjob created
一覧表示
作成されたCronJobの一覧を確認するには、以下のコマンドを使用します。
bash
kubectl get cronjobs
出力例:
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
my-cronjob */5 * * * * False 0 <none> 10s
NAME
: CronJobの名前。SCHEDULE
: 設定されたCron式。SUSPEND
: CronJobが一時停止されているか (True
) またはアクティブか (False
)。ACTIVE
: 現在実行中のJobの数。LAST SCHEDULE
: 最後にJobがスケジュールされた時刻。まだ一度もスケジュールされていない場合は<none>
。AGE
: CronJobが作成されてからの経過時間。
詳細情報の確認
特定のCronJobの詳細情報を確認するには、describe
コマンドを使用します。
bash
kubectl describe cronjob my-cronjob
このコマンドは、CronJobの現在の設定、状態、および関連するイベント(Jobの作成、スケジュールのスキップなど)を表示します。特に、Events
セクションはJobがスケジュールされたかどうか、エラーが発生していないかなどを確認するのに役立ちます。
作成されたJobとPodの確認
CronJobによって実際に実行されたJobや、そのJobによって作成されたPodを確認することで、タスクの実行状況を把握できます。
-
Jobの一覧を確認:
bash
kubectl get jobs
CronJobによって作成されたJobの名前は、通常[cronjob-name]-[timestamp]
の形式になります。
出力例:
NAME COMPLETIONS DURATION AGE
my-cronjob-1678886400 1/1 5s 2mCOMPLETIONS
: 完了したPodの数/必要な完了数。Jobが完了しているかどうかが分かります。DURATION
: Jobの実行時間。AGE
: Jobが作成されてからの経過時間。
-
Podの一覧を確認:
bash
kubectl get pods
Jobによって作成されたPodの名前は、通常[job-name]-[random-string]
の形式になります。
出力例:
NAME READY STATUS RESTARTS AGE
my-cronjob-1678886400-abcde 0/1 Completed 0 2mSTATUS
: Podの状態 (Pending
,Running
,Succeeded
,Failed
,Completed
など)。Completed
はタスクが正常終了したことを意味します。Failed
はタスクが失敗したことを意味します。RESTARTS
: コンテナの再起動回数。backoffLimit
の設定によって再起動が発生します。
ログの確認
タスクが期待通りに実行されたか、エラーが発生していないかなどを確認するには、Jobが作成したPodのログを見ます。
まず、ログを見たいPodの名前を確認します(kubectl get pods
コマンドで確認)。
bash
kubectl logs my-cronjob-1678886400-abcde
これにより、Pod内のコンテナが標準出力や標準エラー出力に出力した内容を確認できます。これがバッチ処理の実行結果やデバッグ情報の主要なソースとなります。
削除
CronJobとその履歴(作成されたJobとPod)を削除するには、以下のコマンドを使用します。
bash
kubectl delete cronjob my-cronjob
これにより、CronJobリソース自体が削除され、それ以降新しいJobは作成されなくなります。また、デフォルトではそのCronJobによって作成されたJobやPodも一緒に削除されます(Kubernetesのガーベージコレクション機能)。
CronJobの実行例
ここからは、具体的なタスクをCronJobとして設定する例をいくつか見ていきましょう。
例1: 定期的な「Hello, world!」出力
最も基本的な例として、数分おきに簡単なメッセージを出力するタスクをCronJobで実行してみます。これはCronJobの設定方法を学ぶのに最適です。
目的: 5分ごとに簡単なメッセージを標準出力する。
マニフェストファイル (cronjob-hello.yaml
):
yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello-cronjob
spec:
schedule: "*/5 * * * *" # 5分ごとに実行
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox:1.36.1 # 小さくシンプルなイメージ
command: ["/bin/sh", "-c"] # シェルスクリプトを実行
args: ["date; echo Hello from the Kubernetes cluster"] # シェルスクリプトの内容
restartPolicy: OnFailure # 失敗したら再起動
backoffLimit: 2 # 最大2回まで再起動を試みる
successfulJobsHistoryLimit: 3 # 成功履歴を3つ保持
failedJobsHistoryLimit: 1 # 失敗履歴を1つ保持
設定のポイント:
schedule: "*/5 * * * *"
: これにより、CronJobは5分ごとにJobを作成しようとします。image: busybox
: 非常に小さく、シェルや基本的なコマンドが使える軽量なイメージです。このようなシンプルなタスクに適しています。command: ["/bin/sh", "-c"]
,args: [...]
:/bin/sh -c "date; echo Hello from the Kubernetes cluster"
というシェルコマンドを実行します。restartPolicy: OnFailure
: コンテナの実行中にエラーが発生した場合(終了コードが0以外の場合)、Podは再起動されます。backoffLimit: 2
: Podが最大2回まで再起動されてもなお失敗する場合、Job全体が失敗と見なされます。
実行手順:
- 上記のYAMLファイルを作成し、
cronjob-hello.yaml
として保存します。 - CronJobを作成します。
bash
kubectl apply -f cronjob-hello.yaml - CronJobが作成されたことを確認します。
bash
kubectl get cronjobs
LAST SCHEDULE
が更新され、ACTIVE
が増えるのを待ちます。 - CronJobによってJobが作成されたことを確認します。
bash
kubectl get jobs
hello-cronjob-[timestamp]
という名前のJobができているはずです。COMPLETIONS
が1/1
になっていればJobは成功しています。 - Jobによって作成されたPodを確認します。
bash
kubectl get pods
hello-cronjob-[timestamp]-[random]
という名前のPodができているはずです。STATUS
がCompleted
になっていればPodは正常終了しています。 - Podのログを確認し、メッセージが出力されていることを確認します。Pod名は
kubectl get pods
で確認した名前を使用します。
bash
kubectl logs [pod-name]
出力例:
Mon Mar 15 10:30:00 UTC 2024
Hello from the Kubernetes cluster - しばらく待って再度
kubectl get jobs
やkubectl get pods
を実行すると、新しいJobやPodが5分ごとに作成され、古いJob/PodがsuccessfulJobsHistoryLimit
とfailedJobsHistoryLimit
に従ってクリーンアップされていく様子を確認できます。 - CronJobを削除する場合:
bash
kubectl delete cronjob hello-cronjob
例2: Webサイトのヘルスチェック
外部のWebサイトに定期的にアクセスし、その応答を確認するタスクをCronJobで実行します。エラー発生時のリトライ設定も試してみましょう。
目的: 10分ごとに指定のURLにHTTP GETリクエストを送信し、応答を確認する。失敗した場合はリトライする。
マニフェストファイル (cronjob-healthcheck.yaml
):
yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: website-healthcheck
spec:
schedule: "*/10 * * * *" # 10分ごとに実行
jobTemplate:
spec:
template:
spec:
containers:
- name: healthcheck
image: curlimages/curl:8.7.1 # curlコマンドが入ったイメージ
command: ["/bin/sh", "-c"]
args: ["curl -f https://www.google.com || exit 1"] # -f はHTTPエラーコードを返した場合に終了コード1を返す
restartPolicy: OnFailure # エラー終了した場合のみPodを再起動
backoffLimit: 3 # Podの再起動を最大3回まで試みる
activeDeadlineSeconds: 60 # Job全体の実行時間上限を60秒とする
successfulJobsHistoryLimit: 2
failedJobsHistoryLimit: 5
設定のポイント:
schedule: "*/10 * * * *"
: 10分ごとにJobを実行します。image: curlimages/curl
:curl
コマンドが使えるイメージです。args: ["curl -f https://www.google.com || exit 1"]
: 指定のURLにアクセスします。curl -f
はサーバーがエラー応答(4xxや5xx)を返した場合に、curl
コマンド自体がエラー終了(終了コード22)するようにします。|| exit 1
は、curl -f
がエラー終了した場合に、シェルの終了コードを1に設定します。これにより、コンテナがエラー終了したとKubernetesに認識させることができます。restartPolicy: OnFailure
: コンテナがエラー終了した場合、Podは再起動されます。backoffLimit: 3
: Podの再起動を最大3回まで試みます。合計4回の実行(初回 + 3回リトライ)が失敗すると、Jobは失敗とマークされます。activeDeadlineSeconds: 60
: もし何らかの問題でJobが60秒経っても完了しない場合、Jobは強制的に終了(キャンセル)され、失敗とマークされます。これにより、実行時間の長いタスクがクラスターリソースを占有し続けることを防ぎます。
実行手順:
- 上記のYAMLファイルを作成し、
cronjob-healthcheck.yaml
として保存します。 - CronJobを作成します。
bash
kubectl apply -f cronjob-healthcheck.yaml - CronJob、Job、Podの状態を監視します。
bash
kubectl get cronjobs
kubectl get jobs
kubectl get pods - しばらくするとJobとPodが作成され、Webサイトへのアクセスが試みられます。通常は成功して
Completed
状態になるはずです。 - Podのログを確認します。
bash
kubectl logs [healthcheck-pod-name]
成功していれば、HTTPレスポンスボディ(通常はGoogleのトップページのHTML)が表示されるか、何も表示されない(標準出力が空)はずです。 - エラー時の挙動を確認する場合:
https://www.google.com
の代わりに存在しないURLやエラーを返すURLを指定してマニフェストを修正し、再度kubectl apply -f ...
してみてください。Jobが失敗し、PodがCrashLoopBackOff
を経由して最終的にFailed
状態になるのが確認できるはずです。リトライの様子はkubectl describe pod [failed-pod-name]
やkubectl logs [failed-pod-name]
で確認できます。backoffLimit
に達すると、JobはFailed
となります。 - CronJobを削除する場合:
bash
kubectl delete cronjob website-healthcheck
例3: データバックアップ(簡単なシミュレーション)
定期的に「データをバックアップする」というタスクをシミュレーションします。実際には、バックアップ対象のデータにアクセスしたり、バックアップ先(S3、別のボリュームなど)に保存したりする処理が必要になりますが、ここでは簡単なファイル操作を行うスクリプトの実行を例とします。
目的: 毎日深夜0時に、特定のファイルを別の場所にコピーする(シミュレーション)。
マニフェストファイル (cronjob-backup.yaml
):
yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: data-backup
spec:
schedule: "0 0 * * *" # 毎日午前0時0分に実行
# timeZone: "Asia/Tokyo" # 必要に応じてタイムゾーンを指定
jobTemplate:
spec:
template:
spec:
containers:
- name: backup-container
image: busybox:1.36.1
command: ["/bin/sh", "-c"]
args:
- | # ヒアドキュメントで複数行のシェルスクリプトを記述
set -e # コマンドが失敗したら即終了
echo "Starting backup at $(date)"
# バックアップ元ディレクトリの作成 (シミュレーション用)
mkdir -p /data/source
echo "This is the data to be backed up." > /data/source/important_file.txt
# バックアップ先ディレクトリの作成
mkdir -p /backup/daily
# ファイルのコピー
cp -v /data/source/important_file.txt /backup/daily/important_file_$(date +%Y%m%d_%H%M%S).txt
echo "Backup completed successfully."
restartPolicy: OnFailure
backoffLimit: 3
# ttlSecondsAfterFinished: 86400 # 完了後24時間でJobを自動削除 (Kubernetes 1.21+ 推奨)
successfulJobsHistoryLimit: 5
failedJobsHistoryLimit: 10
設定のポイント:
schedule: "0 0 * * *"
: 毎日午前0時ちょうどに実行されます。timeZone: "Asia/Tokyo"
: もし日本標準時 (JST) で午前0時に実行したい場合は、この行を追加します(指定しない場合はUTCの午前0時になります)。args: - | ...
: 複数行のシェルスクリプトをargs
フィールドに記述するために、YAMLのヒアドキュメント記法 (- |
) を利用しています。スクリプト内でset -e
を使うことで、途中のコマンドが失敗した場合にスクリプト全体がエラー終了し、Podが失敗と見なされるようにしています。- この例では、Podの一時的なファイルシステム内に
/data/source
と/backup/daily
ディレクトリを作成し、ファイルコピーを行っています。これはシミュレーションであり、Podが終了するとこれらのファイルは失われます。実際のバックアップタスクでは、PersistentVolumeClaim をマウントしたり、S3やGCSなどの外部ストレージにデータをアップロードしたりする処理が必要です。 successfulJobsHistoryLimit: 5
,failedJobsHistoryLimit: 10
: バックアップタスクは失敗時の原因究明が重要なので、失敗履歴を多めに保持するように設定しています。
実行手順:
- 上記のYAMLファイルを作成し、
cronjob-backup.yaml
として保存します。 - CronJobを作成します。
bash
kubectl apply -f cronjob-backup.yaml - スケジュール時刻(この例では毎日午前0時)を待ちます。または、テストのためにスケジュール時刻を現在時刻から数分後に変更して試すこともできます。
- JobとPodが作成され、実行されることを確認します。
bash
kubectl get jobs
kubectl get pods - Podのログを確認します。
bash
kubectl logs [backup-pod-name]
スクリプトの出力(ファイルのコピー状況など)が表示されるはずです。 - CronJobを削除する場合:
bash
kubectl delete cronjob data-backup
例4: Cron式と各種オプションの組み合わせ
Cron式のより複雑な例と、concurrencyPolicy
などのオプションを組み合わせた例です。
目的: 毎月第1月曜日の午前9時15分に、同時実行を禁止した状態で特定のタスクを実行する。
マニフェストファイル (cronjob-complex.yaml
):
yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: monthly-report-generator
spec:
schedule: "15 9 * * 1#1" # 毎月第1月曜日の9時15分に実行
timeZone: "Europe/London" # 例として別のタイムゾーンを指定
concurrencyPolicy: Forbid # 同時実行を禁止
jobTemplate:
spec:
template:
spec:
containers:
- name: report-generator
image: ubuntu:latest # 例として別のイメージ
command: ["/bin/bash", "-c"]
args: ["echo 'Generating monthly report for $(date)...'; sleep 30; echo 'Report generated.'"] # 30秒かかるタスクをシミュレーション
restartPolicy: OnFailure
backoffLimit: 1 # リトライは1回まで
startingDeadlineSeconds: 300 # スケジュール時刻から最大5分遅延まで許容
successfulJobsHistoryLimit: 2
failedJobsHistoryLimit: 2
設定のポイント:
schedule: "15 9 * * 1#1"
:15
: 15分9
: 9時*
: 毎日(日付に関係なく)*
: 毎月1#1
: 曜日フィールド。1
は月曜日(日曜日を0とした場合)、#1
はその月の第1番目。したがって、「毎月第1月曜日」を意味します。
timeZone: "Europe/London"
: スケジュール評価をロンドンのタイムゾーンで行います。concurrencyPolicy: Forbid
: 前回の実行がまだ完了していない場合に、今回の実行をスキップします。レポート生成など、複数インスタンスが同時に実行されると問題が発生する場合に有用です。startingDeadlineSeconds: 300
: スケジュールされた9時15分から5分(300秒)以内にJobが開始できない場合、その回の実行はスキップされます。これにより、大幅に遅延したJobが後から実行されるのを防ぎます。- タスクのシミュレーションとして
sleep 30
を入れており、実行に30秒かかることを表現しています。
実行手順:
- 上記のYAMLファイルを作成し、
cronjob-complex.yaml
として保存します。 - CronJobを作成します。
bash
kubectl apply -f cronjob-complex.yaml - スケジュール時刻(毎月第1月曜日の9時15分)を待ちます。テストのためには、スケジュールを現在の時刻から数分後に設定して確認します。
- JobとPodが作成され、実行されることを確認します。
bash
kubectl get jobs
kubectl get pods - もし、次のスケジュール時刻が来る前に現在のJobがまだ実行中であった場合(この例では30秒なので可能性は低いですが、
sleep
時間を長くすればシミュレーションできます)、concurrencyPolicy: Forbid
の効果で次のJobが作成されないことが確認できます。kubectl describe cronjob monthly-report-generator
のEvents
セクションにSaw completing job..., skipping next schedule
のようなイベントが表示されることがあります。 - CronJobを削除する場合:
bash
kubectl delete cronjob monthly-report-generator
高度な設定と考慮事項
CronJobを本番環境で安定して運用するためには、いくつかの高度な設定や考慮すべき事項があります。
タイムゾーンの設定 (timeZone
)
前述しましたが、timeZone
フィールドはCronJobのスケジュール評価において非常に重要です。指定しない場合の挙動は環境に依存する可能性があり、予期せぬ時刻に実行されたり、夏時間/冬時間の影響を受けたりするリスクがあります。常に明示的にタイムゾーンを指定することを強く推奨します。一般的にはUTCを使用するか、タスクが特定の地域の時間帯に厳密に依存する場合は、その地域のタイムゾーン(例: “Asia/Tokyo”, “America/New_York”など)を指定します。指定できる値はIANA Time Zone Databaseで定義されている形式です。
同時実行の制御 (concurrencyPolicy
)
concurrencyPolicy
の設定は、リソースの競合やタスクの冪等性を考慮する上で不可欠です。
- Allow: デフォルト。複数のJobが同時に実行されても問題ないタスク(例: 独立したデータ処理タスク)に適しています。リソースが十分にあり、スループットを最大化したい場合に有効です。
- Forbid: 前のJobが完了するまで次のJobを開始させたくない場合(例: データベースバックアップ、ユニークなリソースを操作するタスク)。これにより、タスクが重複して実行されることによる問題を回避できます。ただし、前のJobがハングアップしたり非常に時間がかかったりすると、後続のJobが一切実行されなくなるリスクがあります。
- Replace: 常に最新のスケジュール実行を優先したい場合。前の実行が遅延している場合、それを中断して新しい実行を開始します。実行中のJobを安全に中断できるタスクにのみ使用すべきです。データの不整合やリソースリークを引き起こす可能性があります。
タスクの性質をよく理解し、適切なポリシーを選択してください。
実行履歴の管理 (successfulJobsHistoryLimit
, failedJobsHistoryLimit
, ttlSecondsAfterFinished
)
CronJobはJobを作成し続けるため、そのまま運用すると完了したJobリソースがKubernetesのデータストア(etcd)にどんどん蓄積されていきます。これはetcdのストレージ容量を圧迫したり、APIサーバーのパフォーマンスに影響を与えたりする可能性があります。
successfulJobsHistoryLimit
と failedJobsHistoryLimit
は、完了したJobリソースを自動的にクリーンアップするために使用されます。適切な値を設定することで、必要な履歴を保持しつつ、etcdの負荷を軽減できます。デバッグや監査のためにはある程度の履歴が必要ですが、無制限に保持するのは避けるべきです。
Kubernetes 1.21以降では、Jobリソース自体の ttlSecondsAfterFinished
フィールドを使用することも推奨されています。これはJobが完了した後にそのJobオブジェクトを自動的に削除するまでの秒数を指定します。CronJobのマニフェスト内で jobTemplate.spec.ttlSecondsAfterFinished
を設定することで、この機能を利用できます。これはCronJobの履歴制限設定とは独立して機能しますが、CronJobの履歴制限が機能する前にJobが削除される場合もあります。一般的には、両方の設定を適切に組み合わせるか、より新しい ttlSecondsAfterFinished
を主に使用し、CronJob側の履歴制限は低めに設定(例えば成功0、失敗1など)すると良いでしょう。
エラーハンドリングとリトライ (backoffLimit
, restartPolicy
)
JobやPodが失敗した場合の挙動は、タスクの信頼性に大きく影響します。
restartPolicy: OnFailure
またはNever
: Jobが作成するPodは、タスクが完了するまで実行されることを想定しています。したがって、タスクが失敗した場合にPodを再起動するか (OnFailure
)、再起動しないか (Never
) を設定します。Always
は使用できません。OnFailure
を使うことで、一時的なエラー(ネットワーク瞬断など)から回復できる可能性があります。backoffLimit
:restartPolicy: OnFailure
と組み合わせて使用します。Podがエラー終了した場合に何回まで再起動を試みるかを指定します。この回数を超えてもPodが成功しない場合、Job全体が失敗とマークされます。タスクの性質に応じて適切なリトライ回数を設定することで、堅牢性を高めることができます。ただし、無限にリトライしないように制限を設けることが重要です。
タスクが失敗した際の終了コードを適切に設定することも重要です。Kubernetesは、コンテナの終了コードが0以外の場合にそのPodを失敗と見なします。スクリプトやプログラムの最後に exit [code]
を記述することで、明示的に終了ステータスを制御できます。
Podテンプレートの詳細設定
jobTemplate.spec.template.spec
フィールドでは、通常のPodと同様に詳細な設定が可能です。
- リソース要求・制限:
containers.resources
を設定し、CPUやメモリの使用量を制限することで、単一のバッチ処理がクラスター全体のリソースを枯渇させてしまうことを防ぎます。バッチ処理は大量のリソースを消費することがあるため、この設定は特に重要です。 - ボリュームマウント:
volumes
とcontainers.volumeMounts
を使用して、ConfigMap、Secret、PersistentVolumeClaimなどをPodにマウントできます。これにより、設定ファイルの参照、認証情報の利用、永続的なデータの読み書きなどが可能になります。特に、バックアップ先への保存や、処理対象データの読み込みなどでPersistentVolumeClaimが利用されることがあります。 - ServiceAccount:
serviceAccountName
を指定することで、そのPodがKubernetes APIと連携する際の権限をRBACによって細かく制御できます。例えば、他のリソースの状態を監視したり、ConfigMapを動的に読み込んだりする場合に必要になります。 - ノードセレクション:
nodeSelector
,affinity
,tolerations
などの設定を使用して、特定のノードやノードプールでJobを実行させることができます。これは、特定のハードウェアリソース(例: GPU)が必要なタスクや、特定のゾーンでのみ実行したいタスクなどに有効です。
シークレットやコンフィグマップの使用
データベースの認証情報やAPIキーなど、機密性の高い情報はマニフェストファイルに直接記述すべきではありません。KubernetesのSecretリソースを使用して安全に管理し、Podにボリュームとしてマウントしたり、環境変数として注入したりすることが推奨されます。同様に、設定ファイルなどはConfigMapとして管理し、Podにマウントして利用できます。
“`yaml
Secretとして認証情報を定義 (例: db-credentials)
—
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data:
username:
password:
CronJobマニフェストの一部 (Secretを環境変数として注入)
…
spec:
jobTemplate:
spec:
template:
spec:
containers:
– name: my-batch-job
image: my-batch-image
env:
– name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-credentials
key: username
– name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
# … 他の設定
…
“`
CronJobの停止と再開 (suspend
)
suspend: true
に設定することで、CronJobのスケジュール実行を一時的に停止できます。これは、計画メンテナンス中にバッチ処理の実行を避けたい場合や、特定のCronJobに問題があり、修正作業中に新たなJobが作成されないようにしたい場合に便利です。修正完了後に suspend: false
に戻せば、再びスケジュール実行が開始されます。一時停止中にスキップされたスケジュールについては、startingDeadlineSeconds
の設定によって、可能であれば実行されるか、完全にスキップされるかが決まります。
デバッグ方法
CronJobのデバッグは、以下のステップで行うことが一般的です。
- CronJobリソースの確認:
kubectl get cronjobs
とkubectl describe cronjob [name]
で、CronJob自体の設定(特にschedule
,suspend
,startingDeadlineSeconds
,concurrencyPolicy
,timeZone
)やイベントを確認します。イベントログには、Jobがスケジュールされたか、スキップされたか、Jobの作成に失敗したかなどの情報が含まれていることがあります。 - Jobリソースの確認: スケジュール時刻が過ぎたら、
kubectl get jobs
とkubectl describe job [name]
で作成されたJobを確認します。Jobの状態 (COMPLETIONS
,STATUS
) や、Podの作成状況、Jobのイベントログを確認します。Jobが失敗している場合は、その原因が示唆されていることがあります。 - Podリソースの確認: Jobが作成したPod (
kubectl get pods
,kubectl describe pod [name]
) の状態 (STATUS
,RESTARTS
) を確認します。PodがPending
のままならスケジューリングの問題、CrashLoopBackOff
ならコンテナの起動または実行中の問題、Failed
ならタスクの失敗などが考えられます。Podのイベントログも参照します。 - Podのログ確認: 最も重要なデバッグ手順です。
kubectl logs [pod-name]
で、実際にコンテナ内で実行されたコマンドやスクリプトの標準出力、標準エラー出力を確認します。タスクが失敗した原因(スクリプトエラー、接続エラー、ファイルが見つからないなど)に関する情報がここに記録されているはずです。 - 手動でのJob実行: スケジュールを待たずに、CronJobの定義を使って手動でJobを作成し、即時実行してデバッグすることも可能です。
kubectl create job --from=cronjob/[cronjob-name] [new-job-name]
コマンドを使用します。これにより、CronJobのスケジュールに依存せずに、Jobの定義自体が正しいか、実行環境で問題なく動作するかなどを素早くテストできます。
監視とアラート
本番環境では、CronJobの実行状況を監視し、失敗した場合にはアラートを発生させる仕組みが必要です。
- メトリクス: KubernetesはCronJobやJobの実行に関するメトリクスを公開しています(Prometheusなどで収集可能)。Jobの成功/失敗回数、実行時間、アクティブなJob数などを監視できます。
- ロギング: 各Job実行のログを集中ロギングシステム(Elasticsearch + Kibana, Loki + Grafanaなど)に集約し、検索・分析できるようにしておくと、トラブルシューティングが容易になります。
- アラート: Jobが失敗した場合、またはスケジュール時刻にJobが開始されなかった場合などに、アラートシステム(Alertmanagerなど)を通じて担当者に通知が飛ぶように設定します。Kubernetesのイベントを監視してアラートを生成する方法や、Jobのメトリクスに基づいて閾値アラートを設定する方法などがあります。
トラブルシューティング
CronJobの運用中に発生しうる一般的な問題とその解決策をいくつか紹介します。
CronJobが期待通りに実行されない
- スケジュールの間違い: Cron式が意図した時刻になっていない可能性があります。オンラインのcronチェッカーツールなどで確認するか、テスト用の短い間隔(例:
*/1 * * * *
)で試してみてください。 - タイムゾーン:
timeZone
フィールドが正しく設定されているか確認します。デフォルトのUTCか、意図したタイムゾーンかを確認してください。 startingDeadlineSeconds
超過: スケジュール時刻からstartingDeadlineSeconds
で指定された時間内にJobが開始できなかった場合、その回の実行はスキップされます。リソース不足、コントローラーの遅延などが原因で発生します。kubectl describe cronjob
のイベントログで “Missed scheduled job” や関連するエラーメッセージが出ていないか確認してください。必要に応じてstartingDeadlineSeconds
の値を増やすか、クラスターリソースを増強します。suspend: true
になっている: CronJobが一時停止状態になっていないか確認します。kubectl get cronjobs
またはkubectl describe cronjob
で確認できます。kubectl patch cronjob [name] -p '{"spec":{"suspend":false}}'
で再開できます。concurrencyPolicy: Forbid
で前のJobが実行中のまま:concurrencyPolicy
がForbid
の場合、前のJobが完了しない限り新しいJobはスキップされます。kubectl get jobs
で古いJobがRunning
のままになっていないか確認し、もしそうであれば手動で削除するか、原因を調査してタスクを完了させる必要があります。- CronJobコントローラーの問題: まれに、Kubernetesのコントローラーマネージャー内のCronJobコントローラー自体に問題が発生している可能性があります。コントローラーマネージャーのログを確認する必要があるかもしれません(通常はKubernetesクラスターの管理者が行います)。
Jobが作成されるが失敗する
- Podの起動失敗: Jobが作成したPodが
Pending
,ImagePullBackOff
,ErrImagePull
,CrashLoopBackOff
などの状態になっている場合、Pod自体が正常に起動できていません。kubectl describe pod [pod-name]
でイベントを確認します。イメージのプルに失敗している、コンテナレジストリに認証できない、ボリュームマウントに失敗している、リソースが不足している(Pending状態のまま)などの原因が考えられます。kubectl logs [pod-name]
で、もしコンテナが少しでも起動していればその時点までのログを確認します。
- タスクの実行失敗: Podの状態が
Running
になった後、最終的にFailed
になる場合、コンテナ内のコマンドやスクリプトの実行中にエラーが発生しています。kubectl logs [pod-name]
で、タスクが標準出力や標準エラー出力に出力した内容を確認します。アプリケーション固有のエラーメッセージ、スクリプトのエラー、ファイルが見つからない、外部システムへの接続失敗などがログに出ているはずです。restartPolicy
とbackoffLimit
の設定により、自動的にリトライされているか確認します。kubectl describe pod [pod-name]
のRestarts
カウントを見ます。
- リソース不足: Jobが要求するCPUやメモリがノードで不足している場合、Podが
Pending
状態のままになるか、OOMKilled
(Out Of Memory) で失敗することがあります。jobTemplate.spec.template.spec.containers.resources
の設定を見直すか、クラスターリソースを増強します。 - 設定ミス: 環境変数、ボリュームマウント、コマンド/引数などが正しく設定されていない可能性があります。
kubectl describe pod [pod-name]
やマニフェストファイルを確認してください。SecretやConfigMapが正しくマウントされているか、必要な値がコンテナに渡っているかを確認します。 - RBAC権限不足: ServiceAccountを使用している場合、そのServiceAccountに必要な権限 (Role/ClusterRole と RoleBinding/ClusterRoleBinding) が付与されているか確認します。例えば、ConfigMapを読み取る、Secretをマウントする、他のリソースを操作するといった操作には対応するRBAC権限が必要です。
履歴が溜まりすぎる、またはすぐに消える
successfulJobsHistoryLimit
,failedJobsHistoryLimit
: これらの設定が意図した数になっているか確認します。0
に設定すると、成功/失敗後すぐに削除されます。jobTemplate.spec.ttlSecondsAfterFinished
: JobテンプレートでttlSecondsAfterFinished
が設定されている場合、その秒数が経過するとJobリソース自体が自動的に削除されます。これはCronJobの履歴制限よりも優先して実行される可能性があります。もし履歴を長く保持したい場合は、この値を増やすか設定を削除し、CronJob側の履歴制限に依存するようにします。- Kubernetesクラスターのバージョンによっては、これらの機能の挙動が異なる場合があります。使用しているKubernetesのバージョンに対応したドキュメントを確認してください。
まとめ
KubernetesのCronJobは、従来の cron
コマンドに代わる、コンテナ化された環境のための強力で柔軟な定期実行タスク管理ツールです。Kubernetesの宣言的な設定、自動化、スケーラビリティ、耐障害性といったメリットを活かしながら、データベースのバックアップ、レポート生成、データクリーンアップといった様々なバッチ処理をKubernetesクラスター上で効率的に実行できます。
CronJobの設定は、標準的なcronフォーマットによるスケジュール定義に加え、実行するタスクの具体的な内容をJobテンプレート(その中にPodテンプレートを含む)として詳細に記述します。また、startingDeadlineSeconds
, concurrencyPolicy
, suspend
, successfulJobsHistoryLimit
, failedJobsHistoryLimit
, timeZone
といったオプションを通じて、スケジュールの遅延時の挙動、同時実行の制御、実行履歴の管理、タイムゾーン設定などをきめ細かく制御できます。
適切なCronJobの設定は、タスクの要件(実行間隔、許容される遅延、同時実行の可否、リトライ戦略、必要なリソースなど)を十分に理解することから始まります。特に、cron式の正確な理解、タイムゾーンの明示的な設定、同時実行ポリシーの慎重な選択、そしてリソース制限の設定は、安定した運用にとって非常に重要です。
CronJobの作成と管理は kubectl
コマンドを使って直感的に行え、作成されたJobやPodの状態、ログを確認することで容易に実行状況を把握し、問題発生時にはデバッグを行うことができます。また、監視システムやアラートシステムと連携させることで、本番環境での信頼性をさらに高めることが可能です。
この記事で解説した内容が、皆様がKubernetes上で定期実行タスクを効果的に管理するための一助となれば幸いです。CronJobを適切に活用し、Kubernetesクラスターの可能性を最大限に引き出してください。