あるソフトウェアエンジニアの開発ブログ

ソフトウェアエンジニアリングを中心につらつらと書く

MacにHomebrewとGitとDockerとGitHubをセットアップ

まずは隠しファイル/フォルダを表示する。

defaults write com.apple.finder AppleShowAllFiles TRUE
killall Finder

表示されているか確認。

Homebrewインストー

公式サイトに沿ってインストール。

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew doctor

Your system is ready to brew.

と表示されればおk。

Gitインストー

brew install git

git config設定。

git config --global user.name "YukiToida"
git config --global user.email "yuki.toida@candee.co.jp"

Dockerインストー

docs.docker.com
公式に沿ってStableをインストール。
その後起動する。

GitHubセットアップ

.sshフォルダに鍵を作成する。

cd
mkdir .ssh
ssh-keygen -t rsa

作成した公開鍵をGitHubに登録する。
おしまい。

EC2にDockerでElixir-Phoenixをデプロイする

EC2にDockerを使ってデータを表示するPhoenixアプリをデプロイする。

Phoenixのconfig設定

Producrion用のconfigを書き換える。
ポート4000にロードし、nginxでリバースプロシキさせる。
config/prod.exsが以下。

config :stock_scraping, StockScraping.Endpoint,
  http: [port: 4000],
  url: [host: "example.com", port: 4000]

Dockerfile作成

Phoenixを起動するDockerfileを作成する。
さっそく中身。

FROM elixir
MAINTAINER yuki-toida

RUN apt-get update

# hex
RUN mix local.hex --force && \
    mix local.rebar --force && \
    mix hex.info

# phoenix
RUN mix archive.install https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez

# node npm
RUN apt-get install -y nodejs npm
RUN npm cache clean && npm install n -g
RUN n stable && ln -sf /usr/local/bin/node /usr/bin/node
RUN apt-get purge -y nodejs npm

# inotify-tools
RUN apt-get install -y inotify-tools

EXPOSE 4000

# git repository
RUN git clone https://github.com/yuki-toida/stock_scraping.git root/stock_scraping
WORKDIR /root/stock_scraping
RUN chmod +x run.sh
ENTRYPOINT ["./run.sh"]
CMD ["dev"]

Elixirの公式イメージを使って公式サイトの手順でPhoenixをインストール。
node.jsとnpmをインストールし、古いパッケージをパージ。
エントリーポイントをrun.shとする。以下。

#!/bin/bash

git reset --hard HEAD
git pull origin master

mix deps.get

npm install

MIX_ENV=$1 mix compile
MIX_ENV=$1 mix phoenix.server

環境変数にprodを設定すると、mix compileが必須になるのがポイント。

EC2にログインしDockerイメージをプルする

docker pull yukitoida/stock_scraping

Dockerコンテナを起動させる

docker run --net="host" yukitoida/stock_scraping prod

これでlocalhost:4000にPhoenixアプリがロードされてるはず。
前回、nginxの設定は終わってるので、リバースプロシキされるはず。
実際のURLがこちら。株カレンダー
なんというクソUI、気が向いたらUIをちゃんと作る。

AWS EC2 に nginx をインストールしリバースプロシキさせる

EC2でPhoenixアプリをグローバルに公開するための設定。

port80を公開する

EC2に適用しているセキュリティグループのインバウンドルールに下記を追加。

タイプ プロトコル ポート範囲 送信元
HTTP TCP 80 0.0.0.0/0

これでポート80をグローバルに公開できる。

nginxのインストー

パッケージ情報確認。

sudo yum info nginx

読み込んだプラグイン:priorities, update-motd, upgrade-helper
利用可能なパッケージ
名前                : nginx
アーキテクチャー    : x86_64
エポック            : 1
バージョン          : 1.10.2
リリース            : 1.30.amzn1
容量                : 534 k
リポジトリー        : amzn-main/latest
要約                : A high performance web server and reverse proxy server
URL                 : http://nginx.org/
ライセンス          : BSD
説明                : Nginx is a web server and a reverse proxy server for HTTP, SMTP, POP3 and
                    : IMAP protocols, with a strong focus on high concurrency, performance and low
                    : memory usage.

↑のように表示されていれば利用可能なので、インストール。

sudo yum install nginx

インストールされたか確認。

nginx -V

built by gcc 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC) 
built with OpenSSL 1.0.1k-fips 8 Jan 2015

nginx を起動する

sudo nginx

プロセスを確認。

ps -ef | grep nginx

root      9069     1  0 17:43 ?        00:00:00 nginx: master process nginx
nginx     9070  9069  0 17:43 ?        00:00:00 nginx: worker process
ec2-user  9072  8991  0 17:43 pts/0    00:00:00 grep --color=auto nginx

起動している。
EC2のパブリックIPでアクセスできるか確認する。
nginxのデフォルトページが表示されたらおk。

nginx 自動起動設定

sudo service nginx start
sudo chkconfig nginx on
sudo chkconfig --list nginx

nginx           0:off   1:off   2:on    3:on    4:on    5:on    6:off

これで自動起動設定完了。

nginx config 設定

Phoenixlocalhost:4000をリッスンしている。
それを[パブリックIP]:80でリバースプロシキ。
/etc/nginx/conf.d/local.confが以下。

upstream phoenix {
  server localhost:4000 max_fails=5 fail_timeout=5s;
}

server {
  listen 80;
  server_name [パブリックIP]

  location / {
    allow all;

    # Proxy Headers
    proxy_http_version 1.1;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-Cluster-Client-Ip $remote_addr;

    # The Important Websocket Bits!
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    proxy_pass http://phoenix;
  }
}

パブリックIP文字列が長すぎてハッシュ化出来ないと nginx に怒られたので、 /etc/nginx/nginx.confに下記追加。

server_names_hash_bucket_size 128;

これで準備完了。
あとはPhoenixをデプロイして、Dockerコンテナ内でlocalhost:4000でアプリをホストすればいけるはず。
次回やる。

AWS EC2 にcronを設定し定期的にDockerコンテナを実行する

東京株式市場は15時大引けなので毎日18時に実行するよう設定する。

EC2にDockerをインストー

# パッケージ更新
sudo yum update -y

# dockerインストール
sudo yum install -y docker

# dockerサービス起動
sudo service docker start

# ec2-user を dockerグループに追加しsudoなしで実行できるように
sudo usermod -a -G docker ec2-user

Dockerイメージをプル

イメージをプルして、コンテナ実行ファイルを作成する。

docker pull yukitoida/stock_scraping_batch

以下実行ファイル/home/ec2-user/docker/run-batch.sh

#!/bin/sh/

docker run --rm --net="host" yukitoida/stock_scraping_batch prod

cron を設定する

crontab -eコマンドを実行する。

MAILTO=""
DIR="/home/ec2-user/docker"
00 18 * * 1-5 /bin/bash $DIR/run-batch.sh > $DIR/logs/`date +\%Y\%m\%d_\%H\%M\%S`.log

MAILTO=""にすることで実行後メールを無効化する。
その代わりに、ファイル名を日付にしログを残す。
crontab -lで登録内容を確認する。

これで平日18時に株価をスクレイピングしてMySQLに保存できるようになる。

Elixir Mix.Configで環境毎にConfigを使い分ける

開発環境により使用するConfigを使い分ける。
流れとしては、Mix.Configにimport宣言を追加し環境ごとのConfigファイルを作成する。
コンパイル時、環境変数を設定しConfigを使い分ける。

Mix.Configの修正

Mix.Config – Mix v1.4.5
import_config "#{Mix.env}.exs"宣言を追加する。
以下config/config.exs

use Mix.Config

import_config "#{Mix.env}.exs"

config :stock_scraping, ecto_repos: [StockScrapingBatch.Repo]

Configファイル追加

dev.exs prod.exs を追加する。
以下config/dev.exs

use Mix.Config

config :stock_scraping_batch, StockScrapingBatch.Repo,
  adapter: Ecto.Adapters.MySQL,
  database: "stock_scraping",
  username: "ytoida",
  password: "",
  hostname: "127.0.0.1",
  port: 3306

環境変数を設定しコンパイルする

DockerfileにENTRYPOINTを定義し、引数で環境変数を渡すようにした。
以下Dockerfile

FROM elixir
MAINTAINER yuki-toida

RUN git clone https://github.com/yuki-toida/stock_scraping_batch.git root/stock_scraping_batch

WORKDIR /root/stock_scraping_batch

RUN mix local.hex --force && \
    mix local.rebar --force && \
    mix hex.info

RUN chmod +x run.sh

ENTRYPOINT ["./run.sh"]

CMD ["dev"]

以下run.sh

#!/bin/bash

# git pull
git pull origin master

# create executable shell script
mix deps.get
MIX_ENV=$1 mix escript.build

# execute
./stock_scraping_batch

これで引数無しでdocker runした場合はdev環境。
prod環境にしたい場合は、docker run --net="host" [イメージ名] prodで引数に指定する。

DockerコンテナからDockerホストMySQLに接続する

スッとMySQLに繋げなかったのでちょっと調べた。

Dockerネットワークの種類

Docker コンテナ・ネットワークの理解 — Docker-docs-ja 1.13.RC ドキュメント
ここを見ながら概要をつかむ。
Dockerインストール時、3つのネットワークが作成される。

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
d1dbc2003e68        bridge              bridge              local
c16c847feff0        host                host                local
27dc4c232fed        none                null                local

Dockerコンテナ起動時にオプションでネットワークを指定する

指定しないとデフォルトのbridgeが適用される。
それだと、Dockerコンテナに割り当てられたIPをMySQLがリッスンする必要があり、
my.cnfbind-address=<DockerコンテナIP>を指定する必要がある。
めんどくさいので、hostを指定する。
ホストネットワークは、DockerコンテナにDockerホストのネットワークスタックを共有する設定。

MySQLユーザーのHostを書き換える

Dockerコンテナからlocalhostへの接続は出来ないため、127.0.0.1でアクセスする。
よって、MySQLユーザーのHostを変更する。

rename user 'ytoida'@'localhost' to 'ytoida'@'127.0.0.1';

変更されたか確認する。

select User, Host from mysql.user;

アプリケーションからのMySQL接続ホストを127.0.0.1にする

config/config.exsを修正する。

config :stock_scraping_batch, StockScrapingBatch.Repo,
  adapter: Ecto.Adapters.MySQL,
  database: "stock_scraping",
  username: "ytoida",
  password: "",
  hostname: "127.0.0.1",
  port: 3306

Dockerコンテナ起動

ネットワークオプションをhostにして起動する。

docker run --rm --net="host" yukitoida/stock_scraping_batch

実際のDockerfileの中身は以下。

FROM elixir
MAINTAINER yuki-toida

RUN git clone https://github.com/yuki-toida/stock_scraping_batch.git root/stock_scraping_batch

WORKDIR /root/stock_scraping_batch

RUN mix local.hex --force && \
    mix local.rebar --force && \
    mix hex.info

RUN chmod +x run.sh

CMD ["./run.sh"]

run.shの中身は以下。

#!/bin/bash

# git pull
git pull origin master

# create executable shell script
mix deps.get
mix escript.build

# execute
./stock_scraping_batch

最後の./stock_scraping_batchバッチ処理を実行する。
正常にMySQLにアクセス出来るはず。

Dockerfileを作成し、DockerHubで自動ビルドを行う

早速Dockerfileを作成していく。

公式 elixir Dockerイメージを使う

https://hub.docker.com/_/elixir/
OSは、16.04.1-Ubuntu だった、サイズが大きいので最適化したほうがいい。

FROM elixir
MAINTAINER yuki-toida

RUN git clone https://github.com/yuki-toida/stock_scraping_batch.git root/stock_scraping_batch

WORKDIR /root/stock_scraping_batch

RUN mix local.hex --force && \
    mix local.rebar --force && \
    mix hex.info

RUN chmod +x run.sh

CMD ["./run.sh"]

この数行に何時間かかったんだろうか。。。
Dockerfileの文法を学ぶのと、デバッグ(build)に時間がかかることで手間取った。
Dockerfile リファレンス — Docker-docs-ja 1.13.RC ドキュメント

DockerHub 自動ビルド

githubにプッシュすると、DockerHub検知してが自動でビルドをしてくれる。
Build Detail タブに現在のステータスが表示される(動作確認済み)。
前回記事参照。
こちらがGitHubリポジトリ
GitHub - yuki-toida/stock_scraping_batch
こちらがDockerHubリポジトリ
https://hub.docker.com/r/yukitoida/stock_scraping_batch/

DockerHub からイメージをプルし実行

DockerHubからプルしてくる。

docker pull yukitoida/stock_scraping_batch

実行する。

docker run --rm -it yukitoida/stock_scraping_batch

Tips

dockerコンテナ全削除コマンド。

docker rm -f `docker ps -a -q`

dockerイメージ全削除コマンド。

docker rmi -f `docker images -q`