docker環境からcronを定期実行させるのに苦戦した話

## 概要
はじめまして。アドベントカレンダーの13日を担当します。
今回は件名にあるとおり、ローカルのdocker環境で処理を定期実行するためにcronを使用した話をまとめようと思います。
少々長くなりますがお付き合いください。

## 要件
今回実装したい処理の要件は以下になります。
* WEBサイトの稼働サーバーに月1回作成されるレポートファイルをローカルに取得する（踏み台サーバーを経由する必要あり）
* ファイルの中身を取得し、その内容をbacklogAPIを用いて新規登録させる。担当者を報告先のアカウントに設定する。
* 新規登録した課題は「未対応」となるため「処理済み」とステータスを変える。

というのが要件です。
「稼働サーバーから直接API投げればよくない？」と思われそうですがセキュリティの関係上ローカルのPCからAPIを実行する必要があり、この要件で実装をしていきます。

## 実装内容
今回はdocker内PHPコンテナ内に実装した処理をホストのubuntu環境で定期実行設定するようにします。
### 稼働サーバーのレポートファイルを取得する
まず稼働サーバーへの接続設定をおこないます。
実行ユーザーのディレクトリ内に.sshディレクトリを作成し、configファイルを以下のように記述します。

``` config
Host {踏み台サーバー名}
 HostName {踏み台サーバーのIP}
 User {実行ユーザー}
 IdentityFile {秘密鍵ファイルの場所}

Host {稼働サーバー名}
 HostName {稼働サーバーのIP}
 User {実行ユーザー}
 IdentityFile {稼働サーバーへの接続鍵}
 ProxyJump {踏み台サーバーのHost}
```

このように設定すると、ssh {稼働サーバー名}でローカルから踏み台サーバー経由で稼働サーバーへログインすることができました。

コンテナ内に直接ディレクトリを作成するとdockerの起動時に毎回ディレクトリが削除されてしまうため、永続ボリューム等に上記のディレクトリを設定をおこない、起動時に実行ユーザーディレクトリにコピーすると毎回自動でディレクトリを作成してくれます。

注意点としてはコピー時に.sshディレクトリの権限を700、その他のファイル（config,鍵ファイル等）は権限を600にする必要があります。chmod ◯◯◯ {ファイルorディレクトリ}で権限を変えましょう。

これで稼働サーバーのファイルを取得できるようになりました。

```
scp {稼働サーバーのファイル} {ローカルの置き場所}
```
でレポートファイルをローカルに置いてしまいましょう。

### レポートファイルをbacklogAPIで課題登録する
backlogはAPIドキュメントを用意してくれているのでこれを参考にします。
https://developer.nulab.com/ja/docs/backlog/#

今回は新規課題登録のAPIを実行します。
``` backlog.php
$host = 'backlogホスト';
$apiKey = 'ユーザー設定から取得したAPIキー';

$params = array(
    'projectId' => '課題を登録するプロジェクトのID',
    'summary' => '課題のタイトル',
    'issueTypeId' => '課題の種別ID',
    'assigneeId' => '担当者のID'
    'description' => '課題詳細、取得したレポートをここに添付する'
);

$headers = array('Content-Type:application/x-www-form-urlencoded');
$context = array(
    'http' => array(
        'method' => 'POST',
        'header' => $headers,
        'ignore_errors' => true
    )
);

$url = 'https://' . $host . '/api/v2/issues?apiKey=' . $apiKey . '&' . http_build_query($params, '', '&');
$response = json_decode(@file_get_contents($url, false, stream_context_create($context)));

```
このようにすると新規で課題が登録され、課題の情報がresponseに格納されます。

### 登録した課題を処理済みに変更する
今回は報告用のチケットを提出する際、チケットを「処理済み」にする必要があります。
課題情報の更新のAPIはbacklog.phpの処理に以下を追記します。

``` backlog.php
$id = $response->id; // idに登録した課題のキーが格納されている
$params = array(
    'statusId' => 3 // 1:未対応 2:処理中 3:処理済み 4:完了
);

$headers = array('Content-Type:application/x-www-form-urlencoded');
$context = array(
    'http' => array(
        'method' => 'PATCH',
        'header' => $headers,
        'ignore_errors' => true
    )
);

$url = 'https://' . $host . '/api/v2/issues/' . $id .  '?apiKey=' . $apiKey . '&' . http_build_query($params, '', '&');
$response = json_decode(@file_get_contents($url, false, stream_context_create($context)));

```
これで登録した課題のステータスを変更することができました。
要件を満たすPHPファイルの作成完了です。

### 作成した処理をcronにて定期実行させる
docker環境のcrontabに下記を記述することで定期実行ができました。
今回は月初の報告になるので毎月1日9時に実行する設定とします。
docker環境のディレクトリでないとdocker-composeが動かないためPHPファイル実行前にcdで場所を変える必要があります。（今回一番つまづいた・・）

``` crontab 
SHELL=$SHELL
PATH=$PATH

0 9 1 * * cd {dockerディレクトリ}; /usr/local/bin/docker-compose exec -T php /bin/bash -c "php {上記で作成したPHPファイルの場所}" > {ログを出す場合は出力先} 2>&1
```

これで無事毎月のレポート提出を自動化することができました。

## まとめ
最後までみていただきありがとうございます。
dockerの仕様の勉強、backlogAPIの勉強、crontabの勉強ができ、為になる作業だったと思います。
つまづく箇所って意外と小さなことだったりしますよね。
今後の誰かのつまづきの助けになればと思います。