Mackerelの環境構築もろもろ

# TL;DR;
試験的にalpineにMackerelを導入したいんだけど、公式のインストール手順で再三迷子になった。
なんかいい方法ないかなと思ってとりあえず模索してみた結果を書いていく。

# 試してみた環境
* windows10 (スペックは割愛)
* Docker (試験的にnginx:1.14.0-alpineイメージで実施)
* ⇒alpine(Linuxの軽量版)
* docker-composeでオーケストレーション対応(後からプロキシサーバと連携したりしやすいように)

# 公式にあるバイナリでインストールする方法
公式のインストール手順は以下

```
curl -LO https://mackerel.io/file/agent/tgz/mackerel-agent-latest.tar.gz
tar xvzf mackerel-agent-latest.tar.gz
cd mackerel-agent
```

ただ、alpineは`curl`コマンドが標準でなかったのでまずcurlコマンドを実行できるようにする必要がある。
Dockerfileに以下を書くことでイメージビルド時にcurlコマンドが出来るようにする。

```Dockerfile
RUN apk update && apk add curl
```
これでcurlのaddが出来るので先述したバイナリのインストールコマンドを実行できる。
まとめるとこんな感じ

```Dockerfile
# curl インストール
# Mackerel-agent もろもろダウンロード
RUN apk update && apk add curl \
    && curl -LO https://mackerel.io/file/agent/tgz/mackerel-agent-latest.tar.gz \
    && tar xvzf mackerel-agent-latest.tar.gz

```

これでとりあえずコンテナの中にmackerel-agentのダウンロードができるようになる。
ただ少し問題があって、上記のままだとイメージビルド時にmackerel-agentはコンテナのルート直下に配置される。
つまりmackerel-agent コマンドを実行する前にパスを通したりしないといけない。これが面倒くさい。

それにコンテナ内で`ls`したりしてディレクトリ漁る時にルートにmackerel-agentが出てくるのがなんとなく気に入らない。あるべき場所にあってくれた方がすっきりする。
だったら普通にインストールする場合と同じように配置してやればいいんでない？ということでコンテナ起動時にシェルスクリプトを実施するコマンドを追記し、
ファイルの配置はそのシェルスクリプトで実行するようにしてあげることにした。
以下が今回のDockerfileの全文。startup.shを/binにコピーして、コンテナ起動時に実行するようにしてあげた。

```Dockerfile:Dockerfile
FROM nginx:1.14-alpine

# default.confをコンテナにコピー(ここはnginxのお話なので今回スルー)
COPY default.conf /etc/nginx/conf.d/default.conf

# startup.shを/bin直下に配置
COPY startup.sh /bin/startup.sh

# curl インストール
# Mackerel-agent インストール
RUN apk update && apk add curl \
    && curl -LO https://mackerel.io/file/agent/tgz/mackerel-agent-latest.tar.gz \
    && tar xvzf mackerel-agent-latest.tar.gz

# コンテナ起動時にstartup.shを実行
CMD sh /bin/startup.sh
```

ちなみにmackerel-agentをバイナリファイルをダウンロードする場合、コンテナのルートに以下がダウンロードされる。

* mackerel-agent
    * mackerel-agent
    * mackerel-agent.conf

普通にmackerel-agentをインストールする場合のデフォルトの配置場所は
mackerel-agent は /bin直下
mackerel-agent.conf は /etc/mackerel-agent直下
であるためそこにファイルを配置してやれば何も考えずmackerelの恩恵にあやかれる。

先述したstartup.shにて、ルートにmackerel-agentフォルダがあったら所定の位置に移動してあげるスクリプトを組んだ。

```sh
#!/bin/bash

# --------------------------------------------------------------------------------------------
# 初回起動時実行シェル
# mackerel-agent(バイナリファイル)が /mackerel-agent ディレクトリに存在した場合/binに移動する
if [ -e mackerel-agent/mackerel-agent ]; then

    mv /mackerel-agent/mackerel-agent /bin/mackerel-agent

fi

# mackerel-agent.confが /mackerel-agent ディレクトリに存在した場合/etc/mackerel-agentに移動する
if [ -e mackerel-agent/mackerel-agent.conf ]; then

    mkdir /etc/mackerel-agent
    mv /mackerel-agent/mackerel-agent.conf /etc/mackerel-agent/mackerel-agent.conf

fi

# ルートにmackerel-agent-latest.tar.gzが存在する場合削除
if [ -e mackerel-agent-latest.tar.gz ]; then

    rm mackerel-agent-latest.tar.gz

fi

# ルートに存在する/mackerel-agent内にファイルが存在しない場合当該ディレクトリを削除
if [ -e /mackerel-agent ]; then

    rm -r mackerel-agent

fi

# --------------------------------------------------------------------------------------------
```

これでとりあえず通常インストール時と同じ場所にバイナリファイルとconfファイルが作成できるのと、
ルートにある空になったmackerel-agentフォルダを削除できる。

あとはコンテナ起動時にmackerel-agentを実行するスクリプトを追記すれば完成。
startup.shの全文は以下

```sh:startup.sh
#!/bin/bash

# --------------------------------------------------------------------------------------------
# 初回起動時実行シェル
# mackerel-agent(バイナリファイル)が /mackerel-agent ディレクトリに存在した場合/binに移動する
if [ -e mackerel-agent/mackerel-agent ]; then

    mv /mackerel-agent/mackerel-agent /bin/mackerel-agent

fi

# mackerel-agent.confが /mackerel-agent ディレクトリに存在した場合/etc/mackerel-agentに移動する
if [ -e mackerel-agent/mackerel-agent.conf ]; then

    mkdir /etc/mackerel-agent
    mv /mackerel-agent/mackerel-agent.conf /etc/mackerel-agent/mackerel-agent.conf

fi

# ルートにmackerel-agent-latest.tar.gzが存在する場合削除
if [ -e mackerel-agent-latest.tar.gz ]; then

    rm mackerel-agent-latest.tar.gz

fi

# ルートに存在する/mackerel-agent内にファイルが存在しない場合当該ディレクトリを削除
if [ -e /mackerel-agent ]; then

    rm -r mackerel-agent

fi

# --------------------------------------------------------------------------------------------

# APIKEY設定
mackerel-agent init -apikey='自分のMackerelのAPIKEY'
# mackerel起動
mackerel-agent
```

とりあえず上記のDockerfileとシェルスクリプトで以下をやってくれる

* イメージ作成時にcurlコマンドの実行を可能にし、バイナリファイルのmackerel-agentをダウンロード
* コンテナ作成・起動時にコンテナのルートにあるmackerel-agentフォルダからバイナリファイルとconfファイルをmackerel-agentのデフォルトの位置に移動
* APIKEYの設定および起動


# コンテナ起動方法について
上記のままmackerelを起動するだけで肝心のnginxを起動するところが自動化できていない。
startup.shでmackerelとnginxをどちらも起動しようとすると後から記述した方がどうにもうまく起動せず、何回やっても解決しなかったので、
コンテナ起動用のシェルスクリプトにてnginxを起動する方向でなんとかした。
(デーモンを同時に起動しようとしているから先に書いたデーモン起動でスクリプトが止まっている？っぽいけどよくわかんなかった。)

## イメージビルド＆コンテナ起動
docker-compose.ymlと同じ階層に以下2つのシェルスクリプトを配置

```sh:box_create.sh
#!/bin/sh

eval cd "docker-compose.ymlがあるディレクトリのパス"

# イメージのビルド
eval docker-compose build --no-cache

# コンテナのビルド・起動
eval sh box_start.sh
```

```sh:box_start.sh
#!/bin/sh

eval cd "docker-compose.ymlがあるディレクトリのパス"

# コンテナのビルド・起動
eval docker-compose up -d

# nginx 起動
docker exec -it web-server nginx -g 'daemon off;'

```

## docker-compose.yml
ここが命題ではないのでサンプルとして添付

```yml:docker-compose.yml
nginx: 
  build: ./nginx
  container_name: web-server
  ports: 
    - "8080:80"
  volumes:
    - ./products/:/var/www/products/
  tty: true
```

volumesでymlのある階層にあるproductsをマウントしているため、htmlなどをproducts以下に配置する。

## default.conf
nginxの設定ファイル。
Dockerfileで所定の位置にコピー(詳しくはnginxの仕様に沿うので割愛)

```conf:default.conf
server {
    listen       80;
    server_name  localhost;

    charset utf-8;

    location / {
        root   /var/www/products;
        index  index.html index.htm;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
```

# ファイルの配置
なんかいろいろごちゃっと書いてまとまりが悪くなったので一応ディレクトリの配置。

* server
     * nginx
          * Dockerfile
          * default.conf
          * startup.sh
     * products
          * index.html  
     * docker-compose.yml
     * box_create.sh
     * box_start.sh

# コンテナ起動じゃ！
上記のフォルダ構成で、box_create.sh(二回目以降の起動はbox_start.sh)で実行。
[localhost](http://localhost:8080)にアクセスして適当に用意したindex.htmlが開ければnginxは起動成功
あとはMackerelのホスト確認画面に起動しているコンテナのIDが出ていれば連携完了。これで鯖缶ができるね！！！

# 課題
startup.shはコンテナ起動時毎回実行されるので毎回ルートにmackerel-agentフォルダが存在するかチェックしてしまう。
処理は軽量なので起動に及ぼす影響はほぼ皆無だがなんとなく気持ちが悪いので代案はいつかそのうち考える。多分。
⇒ コンテナ起動してから初回だけ自分でコマンド叩けば済む話だが可能な限りオートメーション化したいというジレンマです。

# まとめ
自分のリマインダをメインに書いたため記事の可読性が酷い。
alpineだと使用できるコマンドも少ないため何なら使えるかと結構躓いたが、curlさえadd出来れば問題なかった。意外。