前回はゴリ押しでgoアプリケーションをawsにデプロイできるようになるところまでやったので、今回はMakefileを書いてコマンド一発でデプロイできるようにしていきたいと思います。
ディレクトリ構成の変更
前回は、適当に構築していたのでbuildするといろんなところにbuildされたファイルが生成されて管理がとても面倒でした。
そこで、今回はディレクトリ構成を変更してまとめてデプロイできるようにしました。
こんな感じ。package.jsonとかをrootに持ってきて、それによってwebpackの出力先がrootに変更になったのが大きな変更点です。
Makefile
Makefileとは
Makefileとは、よしなにコマンドを生成できる設定ファイルです。(説明あってるか不安。。)
[タスク名]: [依存ターゲット1] [依存ターゲット2] ...
[コマンド]
というフォーマットに従って書いていきます。依存ファイルに関しては後述します。
$ make [タスク名]
とすれば実行できます。
依存ターゲット
これはそのタスクが依存するタスクを選択することができる機能です。複数選択できますが順番は保障されません。
また、ターゲットとなるファイルが存在している場合はそのタスクは実行されずにパスされます。
言葉だけではわかりにくいので具体例を挙げると、
build: main static/js/bundle.js
main:
GOOS=linux GOARCH=amd64 go build main.go
static/js/bundle.js
npm run build
このように記述しておくことで、
$ make build
を実行すると、
$ make main
$ make static/js/bundle.js
が実行されてからbuildのコマンドが実行されます。(今回の例では何もコマンドがありませんが。)
しかし、一回実行するとbinaryとbundle.jsが生成されるので2回目は何も起こりません。
これはbuildに時間がかかるファイルなどに有効なそうです。逆に毎回変更したいアプリケーションのbinaryやbudle.jsには向いていません。毎回rm
するか依存ターゲットを使わない設計にしましょう。
今回は、
clean:
rm main
のようにして、必要がなくなったら削除するようにしています。
[追記] 逆にターゲットとなるタスクもファイルもない場合は、makeの時点でこけるようになっています。build: server.go
GOOS=linux GOARCH=amd64 go build main.go
npm run build
として実行すると
$ make build
make: *** No rule to make target `server.go', needed by `build'. Stop.
となってしまいます。
要は、makeは依存関係をよしなにやってくれるといいうことです。
デプロイの手順
方針
デプロイ用にrootにbuildしたものと静的ファイルが作られます。
main(binary)
static/
templates/
これらをtarで固めて、scpでアップロードしてsshしてその中でtarを展開してbinaryを起動という手順です。(tarに関してはこちらを参照)
tarで固める
build:
GOOS=linux GOARCH=amd64 go build main.go
npm run build
zip: build
tar zcvf main.tar.gz main templates/ static/
tarコマンドを使って圧縮されたアーカイブファイル(?ちょっと自信ない)を作成します。zipするにはbuildされたファイが必要になるのでbuildをターゲットにしています。
これを実行することでrootにmain.tar.gzというアップロード用のファイルが作成されます。
scpでアップロード
これは前回とそんなに変わりません。makeに変更しただけです。
upload:
scp -i ~/.ssh/$(PEM_NAME).pem main.tar.gz ec2-user@$(AWS_IP_ADRESS).compute.amazonaws.com:~/app
scp -i ~/.ssh/$(PEM_NAME).pem provisioning/Makefile ec2-user@$(AWS_IP_ADRESS).compute.amazonaws.com:~/app
ついでに、本番環境で実行する用のMakefileもアップロードしています。
汎用性とセキュリティを高めために環境変数を使用しています。
sshしてその先でMakefileを実行
このように分離しているのは、sshで接続した先では同じmakeタスクを継続することができないからです。その代わりにsshと同時に、ssh先で実行するコマンドを指定してtarの展開とbinaryの起動を行います。
ssh:
ssh -i ~/.ssh/$(PEM_NAME).pem ec2-user@$(AWS_IP_ADRESS).compute.amazonaws.com \
cd app/ \&\& \
make start
$ ssh [host]
に続いコマンドを並べることでssh先で実行するコマンドを指定することができます。知らなかった。。
tarの展開とbinaryの実行
ついでにリモートのawsも起動しています。binaryの実行に上二つのタスクを依存させてるだけです。
unzip:
tar zxvf main.tar.gz
rm main.tar.gz
nginx:
sudo service nginx start
# うまくバックグラウンド起動にできないから出力先を変更
start: unzip nginx
./main >> /dev/null &
binaryの実行の出力先をdev/null
にしているのはそうしないとバックグラウンドでうまく起動してくれなかったからです。makeからsshでコマンド指定して実行するには無理があったのかな、、
これの問題点は再起動(再デプロイ)の際にいちいちプロセスを終了させないといけないことです。何か管理するアプリとかを使った方がいいのかな、、
$ make deploy
はい、満を持しての、
deploy: zip
make upload
make clean
make ssh
これで、全部が
$ make deploy
の一発で終わるようになります。感動。
謝辞
@saxsirさん!いつも開催ありがとうございます!
毎週毎週めっちゃ成長できてるのでありがたい限りです!!
来週以降もよろしくお願いします。。そろそろ、VGオフィスにも、、w
Makefileたち
build: main.go
GOOS=linux GOARCH=amd64 go build main.go
npm run build
zip: build
tar zcvf main.tar.gz main templates/ static/
upload:
scp -i ~/.ssh/$(PEM_NAME).pem main.tar.gz ec2-user@$(AWS_IP_ADRESS).compute.amazonaws.com:~/app
scp -i ~/.ssh/$(PEM_NAME).pem provisioning/Makefile ec2-user@$(AWS_IP_ADRESS).compute.amazonaws.com:~/app
ssh: # \の前にスペースないと怒られる
ssh -i ~/.ssh/$(PEM_NAME).pem ec2-user@$(AWS_IP_ADRESS).compute.amazonaws.com \
cd app/ \&\& \
make start
clean:
rm main
rm main.tar.gz
deploy: zip # make deploy前にzipを実行
make upload
make clean
make ssh
# 以下provisioning/Makefile
unzip:
tar zxvf main.tar.gz
rm main.tar.gz
nginx:
sudo service nginx start
# うまくバックグラウンド起動にできないから出力先を変更
start: unzip nginx
./main >> /dev/null &
リポジトリはこちら
Dragon-taro/go-react