Golang+Docker+herokuで何か作ろうとした話

#記事概要
Golang+Docker+herokuで何か作ろうとしてハマった事とか色々まとめるだけの記事。

## 筆者について
- Golang初見。
- herokuはPHPとRailsで触った事がある。
- Dockerは便利すぎてハマりだしてる。

## 採用したもの
- gin  
 - Webサーバライブラリ。
- Realize  
 - ホットリロード。
 - 後述。

## リポジトリ
https://github.com/YanaPIIDXer/QiitaLineBot
試行錯誤の経緯とかはここのコミットログを見れば大体分かる・・・かも。
ちなみに今回ブランチ分岐は無しの方向。

# Golangのホットリロード
「コードを書き換えると自動でビルドが走って、後はブラウザを更新するだけ」と言う機能。

## 導入
[Realizeを使ってGoでホットリロードを実現する](https://qiita.com/godgarden/items/f73e4a717f1a27b9a3b0)
上記記事を参考にRealizeを導入。
・・・が、Realize起動時のビルドは走ってるっぽいがホットリロードは機能しない。

## legacyの有効化
どうもRealizeをDocker（コンテナ）上で動作させるには、legacyを有効化する必要がある模様。
[ここを参照。](https://teratail.com/questions/248617)
.realize.yamlの記述を

```yaml:.realize.yaml
settings:
  legacy:
   force: true
（省略）
```
として再起動したら無事動作。

# herokuへのdeploy

## ポート
ローカル環境で立ち上げている時はポート3000を使用しているが、heroku上で動作させる場合はherokuが指定したポートで処理をしなければならない。

### プログラム側の対応
環境変数「PORT」に値が入っていればheroku上での動作としてそのポートを、入っていなければローカルでの動作としてポート3000を利用するようにしてみよう。

```docker:Dockerfile
# 以下の記述を追加。
ENV PORT=${PORT}
```

```go:main.go
// サーバ起動部分。
var port = os.Getenv("PORT")		// heroku上で動かす場合は指定されたPortじゃないと死なますよ。
if port == "" {
	port = "3000"
}
fmt.Println("Server Port:" + port)
router.Run(":" + port)
```

これでdeployしたら動・・・かなかった。

### コンテナ構成の変更
色々調査しながら、ふとdocker-compose.ymlを眺めると・・・

```yml:docker-compose.yml
 （省略）
    ports:
      - "3000:3000"
    command: realize start --name='server' --run
 （省略）
```

・・・

```yml:docker-compose.yml
    ports:
      - "3000:3000"
```

お　前　か　。
ここもherokuが使ってるポートにしてやらないと動かないんじゃないかな・・・？

色々調べて、以下の記事がヒット。
[golang,docker,mysqlの環境をherokuにデプロイする](https://qiita.com/pokotyan/items/51f28eae698c3f7b4d8c)

この記事にある通りにコンテナ構成を変更。（Realizeはローカルでのみ動作させるように。）
上記の記事ではdocker-compose.ymlをdockersディレクトリ内に配置しているが、同じようにすると動作せず。
多分どこかでパスに問題が出てるんじゃないかな・・・？未調査だけど。
面倒なのでルートディレクトリに別名（docker-compose-local.yml）で放り込むと動作するようになった。

herokuにdeployして、ログを見た感じエラーとかも無さそう。
いざアクセス・・・が、動作せず。
SSL絡みかと思ったが、普通にhttpでアクセスしても同じ結果だった。

### No web processes running
ログをみた所、「No web processes running」と言うエラーメッセージが。
これを調べた所、以下の記事に行き着いた。
[【Heroku】デプロイ後にcode=H14 desc="No web processes running"](https://qiita.com/rebi/items/efd1c36f0a9e46222d80)

記事にある通り、``` heroku ps:scale web=1 ```を叩いたところ、動作はしなかったもののエラーメッセージが変わった。
（記事では「このコマンドを叩いただけでは動作せず、heroku.ymlが必要」との事だったが、自分はRealizeをローカルでのみ動作させるようにする過程で作成済みなのでこのコマンドだけでＯＫだった。）

### App crashed
何かクラッシュしたらしい。
このエラーメッセージで調べたところ、以下の記事がヒット。
[HerokuでApplicationErrorが発生したときの対処法](https://qiita.com/Oakbow/items/1565922ddcdea0ce9ab5)

この記事に書かれていたコマンドで再起動。しかし変わらず。

そこからログを少し遡ると、``` .env Load Failed. ``` 。
「・・・これってさ、.envの読み込み失敗時にそのままエラーとしてreturnしてた時のログだよね？herokuへのdeploy作業の過程でそのエラー処理は撤去したんだけど・・・」
「何かしらの原因で過去のやつが動作しているのでは？」と言う疑いが。

再度deployしてアクセス→router.Runメソッドが走るところまでは確認したがApp crashは解消されず→再度上記記事のコマンドで再起動→ ``` .env Load Failed. ```

気になる事としては、「herokuへのdeploy時、releaseから処理が返ってこない」と言う事。（毎回Ctrl+Cしてる。）
「コマンドがフォアグラウンドで走ってるとか・・・？」とか考えて、適当にENTRYPOINTをlsに変えてみても結果は同じ。
で、ENTRYPOINTがlsのものが動いてる（・・・と思い込んでいる）状態で ``` heroku logs ``` 。
普通にGoのプログラムが動いていた。
・・・まぁ、「処理が返ってこない」と言いながらCtrl+Cで強制的に抜けてるんだからそりゃそうだわな。

### アプリケーションの作り直し
とりあえず ``` heroku destroy ``` で一旦破棄。
``` heroku create ``` で作り直す。
再度pushしてアクセスすると無事動作。
app crashedの原因はよく分からないが、一旦作り直してみるのも手ではある。（今回は「過去のプログラムが動作した」と言う事から、「ゴミが残っている」と言う事が明白だったので。）

ちなみにここでdeploy方法を ``` git push heroku master ``` から ``` heroku container:push web ``` → ``` heroku container:release web ``` にも変更している。
（自分はdocker-composeを使ったビルドしかした事が無く、docker-composeを使わずにコンテナを単体で動かす時にどうやってコンテナ名を付けるのかが分からなかった為。。。これもここで覚えた。）

# 最後に
「GolangをDockerでインストールし、heroku上で動作させる」まででハマったところを色々まとめてみた。
冒頭に書いたリポジトリでのアプリケーション開発活動自体はまだまだ継続するものの、今回の表題である「Golang+Docker+heroku」での動作までは進み、「後はGolang内で色々と実装するだけ」と言う段階に至ったので、ひとまずこの記事は完結とする。
（それに伴い、余計な記述も撤去。）

ここまで来るのに数日を要したが、その分多くのことをインプットできたように思える。
そこでブチ当たった様々な問題とその解決策をなるべくリアルタイムで更新してきた。
「誰かに伝える事」は正直苦手だから色々と拙い所はあると思うが、こういった記事でも役に立ってくれれば幸いである。