ようへいの日々精進XP

よかろうもん

2019 年 01 月 19 日 (土)

ジョギング

yamap.com

自宅をスタートしてマリンメッセを経由して天神を抜けて一時間程度.

日課

  • お休み

香椎

久しぶりに香椎まで.

手羽と大根

奥さんが手羽先と戦っている。

docker-machine と DigitalOcean を使って "頼りになるのは, 近くの VM より遠くの VPS" な docker 環境を整える

tl;dr

個人的に利用している MacBook Air (11-inch, Mid 2012) は, まだ macOS Mojave のアップグレード対象になっていたりして, Apple から見放されていないようなので, しばらくは使い続けようかなと考えています. また, 購入時に奮発してメモリ 8GB にしたお陰で, 基本的な操作 (インターネットを見る, vim で何かを書く) であれば十分現役だと思っています. ということで, 今回, 利用する端末の情報は下記の通りです.

以下, OS の情報.

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.2
BuildVersion:   18C54

以下, ハードウェアの情報.

f:id:inokara:20190119172922p:plain

しかし, Docker for Mac を使っていて, Docker for Mac だけでメモリの使用量が 2GB だったりするのを見ると, 「おおっ」という気分になって Docker 環境を VPS あたりに逃してあげればメモリ使用量を抑えることが出来るよなーという思いから docker-machine と DigitalOcean を使って VPS 上に Docker 環境を揃えてみました.

頼りになるのは, 近くの VM より遠くの VPS

DigitalOcean

すでに DigitalOcean のアカウントは取得済み, アクセストークンも払い出し済みという前提で進めます. また, VPS を起動した後, 仮想マシン (以降は Droplet と呼びます) に対して Firewall の設定等を行いたいので, DigitalOcean が提供する各種リソースをコマンドラインで操作出来る doctl というツールを事前にインストールしておきましょう.

brew install doctl

今回, doctl については, 以下のバージョンを利用します.

$ doctl version
doctl version 1.12.2-release

尚, DigitalOcean の VPS にはいくつかのプラン (インスタンスタイプみたいなもの) がありますが, 今回は, 一番安価な メモリ 1GB, 1vCPU, 25GB SSD のタイプを利用します. このタイプですと, 1 時間あたり $0.007 ドル, 1 ヶ月に換算すると $5 となりますので, 一年稼働し続けても 7000 円程度と, これから MacBook Pro 13 インチあたりを新調するよりはお安く済みそうな気がします.

docker-machine

以下のバージョンの docker-machine を利用します.

$ docker-machine version
docker-machine version 0.16.0, build 702c267f

Docker 用の Droplet を起動

例のごとく, direnv を手元に用意しておくと良いでしょう. 以下のように .envrc の中に DigitalOcean のトークンを書いておきます.

export DIGITALOCEAN_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

以下のように docker-machine を実行します.

docker-machine create \
    --driver digitalocean \
    --digitalocean-access-token=${DIGITALOCEAN_ACCESS_TOKEN} \
    my-docker-host

以下, 実行例です.

$ docker-machine create \
>     --driver digitalocean \
>     --digitalocean-access-token=${DIGITALOCEAN_ACCESS_TOKEN} \
>     my-docker-host
Running pre-create checks...
Creating machine...
(my-docker-host) Creating SSH key...
(my-docker-host) Creating Digital Ocean droplet...
(my-docker-host) Waiting for IP address to be assigned to the Droplet...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with ubuntu(systemd)...
Installing Docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env my-docker-host

docker-machine env my-docker-host を実行して, IP アドレス等を確認しましょう. 以下のように出力されます.

$ docker-machine env my-docker-host
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://xxx.xx.xx.xx:2376"
export DOCKER_CERT_PATH="/Users/user/.docker/machine/machines/my-docker-host"
export DOCKER_MACHINE_NAME="my-docker-host"
# Run this command to configure your shell:
# eval $(docker-machine env my-docker-host)

また, eval $(docker-machine env my-docker-host) を実行して環境変数に指定してしまいましょう.

Firewall を設定する

Droplet を作成するとデフォルトだと Firewall の設定は行われていません. この状態だと, どこからでも SSH アクセスが出来たり, Docker API を叩くことが可能な状態になっています. ただし, SSH でログインするには SSH キーが必要だったり, Docker にリモートアクセスする為のキーが必要だったりするので, 誰でもどこからでもアクセス出来るという状態ではありませんが...気持ち悪いので, 固定 IP からのみアクセスを許可するように Firewall を設定します.

事前に DigitalOcean の Web コンソール上で Firewall の設定をしておきましょう. 今回は MyNetwork という Firewall のエントリを事前に作成しておきましたので, 以下のように Firewall の ID と Droplet の ID を取得して Droplet に Firewall をアタッチします.

FIREWALL_ID=$(doctl compute firewall list --output=json | jq -r '.[]|select(.name | test("MyNetwork")) | .id')
DROPLET_ID=$(doctl compute droplet list --output=json | jq -r '.[]|select(.name | test("my-docker-host")) | .id')
doctl compute firewall add-droplets ${FIREWALL_ID} --droplet-ids ${DROPLET_ID}

一通り設定が終わったら

docker-machine ls してみましょう.

$ docker-machine ls
NAME             ACTIVE   DRIVER         STATE     URL                       SWARM   DOCKER     ERRORS
my-docker-host   *        digitalocean   Running   tcp://xxx.xx.xx.xx:2376           v18.09.1

docker-machine の設定を確認してみましょう.

$ docker-machine config my-docker-host
--tlsverify
--tlscacert="/Users/user/.docker/machine/machines/my-docker-host/ca.pem"
--tlscert="/Users/user/.docker/machine/machines/my-docker-host/cert.pem"
--tlskey="/Users/user/.docker/machine/machines/my-docker-host/key.pem"
-H=tcp://xxx.xx.xx.xx:2376

これで Docker を操作してみましょう

docker ps してみましょう.

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Nginx のコンテナを起動してみましょう.

$ docker run -p 80:80 -d nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
177e7ef0df69: Pull complete
ea57c53235df: Pull complete
bbdb1fbd4a86: Pull complete
Digest: sha256:b543f6d0983fbc25b9874e22f4fe257a567111da96fd1d8f1b44315f1236398c
Status: Downloaded newer image for nginx:latest
6b55bf40f43b261e97c2fcb02c729e9c26867d3aa07787d5cd55d56f42fd799a

ローカルホストではないので, コンテナにアクセスする為に docker-machine ip my-docker-host を実行して Droplet の IP アドレスを確認しつつ , 以下のように実行します.

$ curl $(docker-machine ip my-docker-host) -I
HTTP/1.1 200 OK
Server: nginx/1.15.8
Date: Sat, 19 Jan 2019 08:51:12 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 25 Dec 2018 09:56:47 GMT
Connection: keep-alive
ETag: "5c21fedf-264"
Accept-Ranges: bytes

いい感じです.

後始末

以下のように実行して Docker ホストを削除します. Droplet は一瞬で削除されるので驚きです.

docker-machine rm my-docker-host

以下, 実行例です.

$ docker-machine rm my-docker-host
About to remove my-docker-host
WARNING: This action will delete both local reference and remote instance.
Are you sure? (y/n): y
Successfully removed my-docker-host
$ doctl compute droplet list --output=json
null

以上

頼れるのは「近くの VM より遠くの VPS」というお話でした.

2019 年 01 月 18 日 (金)

ジョギング

  • 朝, 山王公園をゆるりと

日課

  • お休み

今日のランチ

会社の福利厚生で全く違うチームのメンバーとワイワイ言いながらうどんすきを食べた. しかし, ミーティングをすっ飛ばしそうになって焦った.

夕飯

奥さんも遅くなったので, 近所の美味しいと言われている小洒落た中華屋さんで.

tabelog.com

雑な言い方で恐縮だけど, 全部美味しかった. しかも, 〆に食べた白ごま担々麺がサイコーだった.

2019 年 01 月 17 日 (木)

ジョギング

  • お休み

日課

  • お休み

今日のランチ

いつもの仕出し弁当.

おご馳走さまでごわす。

JAWS-UG 福岡もくもく会

Terraform をちゃんとやり直したくて, いにしへの昔に作った Terraform テンプレートを見直しているところ. 雰囲気はわかってきた感. Terraform 以外にも色々とやりたいことが山積. 本も読まなければ.

2019 年 01 月 16 日 (水)

ジョギング

  • 職場から自宅まで 30 分ほど (距離的に 5 〜 6 キロくらい)
  • YAMAP の活動記録をつけるようにしてみた

yamap.com

日課

  • お休み

夕飯

  • 三日目のカレー, 煮込んだカレーは本当に美味しいですよね
  • おでんが食べたい

眠い

寝ても疲れが取れない感じ...

2019 年 01 月 15 日 (火)

ジョギング

  • 職場から自宅まで 45 分ほど (距離的に 9 キロくらい)

日課

  • お休み

久しぶりに

ルーターとか無線 LAN とかの情報を調べている.

夕飯

2 日目のカレー. 煮込まれていて美味しかった.

2019 年 01 月 14 日 (月)

ジョギング

  • お休み
  • 右の太ももに強い張りがあるので, 温めてストレッチを長めに

日課

  • 腹筋 50 回 (申し訳ない程度に)

美味しい中華屋さん

ランチは近所の中華屋さん. 奥さんは黒ごま担々麺, 自分は辛い麺を汗だくで食べた. 駅から少し離れたお店なのに大賑わいで驚いた.

夕飯

久しぶりのカレーライス. 奥さんのカレーは本当に美味しい.

2019 年 01 月 13 日 (日)

ジョギング

  • 山王公園を 30 分くらい
  • 懸垂 x 5 回
  • 右の太ももあたりに強い張りがあるので, 明日は多分休む

日課

  • お休み

学生証を取りにいく

後期がもう終わろうとするところで放送大学の学生証を取りに行った. 学生証が無いと単位認定試験が受けられない為...ところが, 単位認定の日程が別大マラソンの前日と被ってしまったことで, 今季の学生生活は終わった...

夕飯

近所のラーメン屋さん. 鶏塩ラーメン屋さんで醤油ラーメンを食べた. 美味しかったけど, まったく物足りなかった.

さくらのクラウドのシンプル監視を Terraform で管理する 〜 さくらのクラウドのシンプル監視 + Terraform チュートリアル 〜

tl;dr

新しい職場で教えて頂いた「さくらのクラウド」の「シンプル監視」が, その名の通り, 設定もコンセプトも非常にシンプルで扱い易いし, 料金も安くて, とても良いと思ったので触ってみました. また, せっかくなので設定自体は Terraform を使ってコードで管理するようにしてみました.

シンプル監視

シンプル監視について

こちら より引用させて頂きました.

お客様のサーバーやサービスを定期的に監視し、異常が発生した際にメールなどで通知するサービスです。PING監視、HTTP/HTTPSのステータス監視、TCPポートの死活監視等のサーバー死活監視の他に料金アラート設定が可能です。

下図の通り (ドキュメント より引用させて頂きました.), Ping や HTTP, HTTPS 等のプロトコルで対象のホストの死活を監視することが出来ます. また, 興味深いのは, サーバー証明書の期限や FTP ポートの死活や, SMTP ポートの死活, DNS の名前解決, クラウドサービスの請求金額についても監視することが出来る点です.

また, 異常を検知した際には, 標準でメールまたは Slack に通知することが出来るので, サービスを公開したらサクッと簡単な死活監視を始められるというのは素晴らしいと思います.

コスト

さくらのクラウドのオプションサービスとして提供されていて, 以下のような料金体系となっています.

  • 監視対象が IPv4 アドレスで, 且つ, さくらの VPS, さくらの専用サーバ等で提供しているグローバル IP アドレスである場合には無料
  • 上記以外は 1 日 1 円/ 1 監視対象あたり, 月額 21 円/ 1 監視対象あたり
  • SSL サーバー証明書の期限監視については, 上記の料金が適用される

さくらインターネットの各種サービスを使ってサービスを提供している場合には, 使わないと勿体無いような気がします.

設定画面

設定画面は下図のようになっており, とても使いやすい設定画面だと思います.

f:id:inokara:20190114201325g:plain

oreno.tools というサイトを https で監視設定している図です.

Terraform で設定する

ポチポチするのも

苦にならないくらいシンプルな設定画面ですが, 「さくらのクラウド」向け Terraform プロバイダが提供されていますので, Terraform でシンプル監視の設定をコード化してみたいと思います.

github.com

サンプル

以下のサンプルを元に進めます.

github.com

Circle CI でフォーマットのチェックや構文チェックが行えるように .circleci/config.yml を忍ばせています.

コード

特に難しい内容ではありません. リソースを定義する simple-monitoring.tf と, 監視対象の FQDN が定義されている variables.tf に分かれています.

以下, simple-monitoring.tf です.

resource sakuracloud_simple_monitor "http-monitor" {
  count  = "${ length( var.http_endpoints ) }"
  target = "${ element(var.http_endpoints, count.index) }"

  health_check = {
    protocol   = "https"
    delay_loop = 3600
    path       = "/"
    status     = "200"
  }

  notify_email_enabled = true
  description          = "${ element(var.http_endpoints, count.index) } URL Monitoring."
}

resource "sakuracloud_simple_monitor" "ssl-monitor" {
  count  = "${ length( var.ssl_endpoints ) }"
  target = "${ element(var.ssl_endpoints, count.index) }"

  health_check = {
    protocol = "sslcertificate"
  }

  notify_email_enabled = true
  description          = "${ element(var.ssl_endpoints, count.index) } SSL Certificate Monitoring."
}

以下, variables.tf です.

variable "http_endpoints" {
  default = [
    "kome.inokara.com",
    "oreno.tools",
  ]
}

variable "ssl_endpoints" {
  default = [
    "oreno.tools",
    "github.com",
  ]
}

監視対象を追加する

make コマンド化しているので, 以下のように make plan からの make apply で監視対象を追加します.

f:id:inokara:20190114201508g:plain

下図のように監視対象が追加されています.

f:id:inokara:20190114201531p:plain

監視対象の一部を削除する

ここからは, Terraform の世界になるので, シンプル監視に限らず, Terraform を触る上で自分に役立ちそうな事を書いてみます.

f:id:inokara:20190114201555g:plain

以下のように destroy サブコマンドに -target オプションを利用して, 指定したリソースのみを削除します.

make show
~/bin/terraform destroy -target=sakuracloud_simple_monitor.ssl-monitor[1]

terraform show を使うことで, 対象となるリソースを確認することが出来ます.

Web コンソールで設定した内容をインポートする

ある日, 障害が発生したことを契機に急ぎで監視対象を Web コンソールで追加しました. この設定を Terraform に取り込みたいと思います.

画像

github.com をサンプルとして利用させて頂きました.

以下のように, import サブコマンドを利用して Web コンソールで追加したリソースの情報をインポートします.

make show
~/bin/terraform import sakuracloud_simple_monitor.http-monitor[2] ${リソースの ID (シンプル監視においては, リソース ID が該当します)}

インポートした後, variables.tf に関し対象を追加しておきましょう.

variable "http_endpoints" {
  default = [
    "kome.inokara.com",
    "oreno.tools",
    "github.com",
  ]
}

variable "ssl_endpoints" {
  default = [
    "oreno.tools",
    "github.com",
  ]
}

variables.tf に追加することで, 監視対象自体の整合性は実際のリソースと Terraform の状態 (tfstate) との整合性が取れることになります. (細かいパラメータについては整合性が取れていない場合がある為, この後に terraform plan を実行すると差分が出てしまうことがあります.)

以上

さくらのクラウド」の「シンプル監視」が本当にシンプルでイケているサービスであることを確認出来ました. また, Terraform を使うことで監視対象をコードで管理出来ることも確認しました.

それでは, 良い監視とインフラストラクチャー・アズ・コード生活をお過ごし下さい.

ギョームで使うシェルスクリプトを社内に配布する方法を検討した

tl;dr

  • AWS CLI と Docker コマンドを駆使した社内ツール (Bash スクリプト) を社内メンバーが利用出来るように配布する方法を考えてみた
  • 尚, 記事内のコード等については, サンプルスクリプト以外については, あくまでも妄想で書いたコードである為, 実際に動くかどうかは検証していない (すいません)

シェルスクリプトサンプル

下図のように docker build して, ECR に docker login からのコンテナイメージを push するスクリプト.

f:id:inokara:20190113204305g:plain

スクリプト自体は, 以下のリポジトリに登録済み. 本記事内では tool-a という名前で随所に登場する予定.

github.com

配布パターン (1) 〜 Amazon S3 に設置して配布する 〜

S3 バケットの設定

  • Web Site Hosting を有効にする
    • AWS CLI がセットアップされていない環境も考慮して, curlwget だけで始められるようにする
    • バケットポリシーで許可された拠点 (社内の拠点 IP) からのみアクセスを許可するようにする
  • スクリプト自体は Github で管理するので, バケット自体は低冗長化ストレージでちょっとでもコスト削減
  • 必要に応じて, アクセスログを取得するような設定にしておきたいところ

ちなみに, 階層構成は以下のような感じを想定.

$ tree oreno-company-tools.s3-website-ap-northeast-1.amazonaws.com
oreno-company-tools.s3-website-ap-northeast-1.amazonaws.com
├── tool-a
│   ├── script.sh
│   └── setup.sh
└── tool-b
    ├── script.sh
    └── setup.sh

2 directories, 4 files

セットアップシェルスクリプト

以下のようにコマンド一発でセットアップが済ませられるようにセットアップ用のシェルスクリプトを用意する.

curl -s https://oreno-company-tools.s3-website-ap-northeast-1.amazonaws.com/tool-a/setup.sh | bash

setup.sh は実際にインストールされる, tool-a や tool-b のスクリプトが動作する為に必要なツールがインストールされているかチェックするように仕込んでおくと良さそう. 尚, tool-a の場合, AWS CLI や Docker コマンド等の所在がチェックされることになる. 以下のような感じ.

# S3 のエンドポイント URL を指定
S3_URL=s3-ap-northeast-1.amazonaws.com/oreno-company-tools
# ツール名
TOOL_NAME=tool-a

# 画面出力用の関数
function incho() {
  printf "\e[34m$1\e[m\n"
}

function wacho() {
  printf "\e[33m$1\e[m\n"
}

# AWS CLI や docker がインストールされていることをチェック
for cmd in aws docker
do
  which ${cmd} > /dev/null 2>&1
  if [ ! $? -eq 0 ];then
    wacho "[warn] ${cmd} がインストールされていません. ${cmd} をインストールしてから, 改めてお試し下さい."
    exit 1
  fi
done
incho "[info] 依存するツールがインストールされていることをチェックしました."

# スクリプト本体のインストール
if [ -d ${HOME}/bin ];then
  curl https://${S3_URL}/${TOOL_NAME}/script.sh --output ${HOME}/bin/${TOOL_NAME} && chmod +x ${HOME}/bin/${TOOL_NAME}
else
  wacho "[warn] ${HOME}/bin が存在していません. ${HOME}/bin を作成してから, 改めてお試し下さい."
  exit 1
fi
incho "[info] スクリプトをインストールしました."

実際の配布からスクリプトの実行までの流れ

f:id:inokara:20190113205238g:plain

いい感じ.

配布パターン (2) 〜 Docker コンテナで配布する 〜

おっ, S3 よりもモダンな感じ

配布したいスクリプトや依存するツールをコンテナに封じ込めることで, 手元の端末の環境をきれいな状態に保つことが出来るし, なによりも Docker を使うことで OS 環境に依存しない実行環境が手に入ってモダンな感じだぜ.

以下のように, docker コマンドまたは docker-compose コマンド経由 (docker-compose.yml を用意する必要がある) で, 目的とするスクリプトを実行出来る.

# docker コマンドで実行する場合
docker run -t -i \
  -v=/var/run/docker.sock:/var/run/docker.sock \
  -v=$(pwd):/work \
  -v=${HOME}/.aws:/root/.aws \
  -w=/work \
  oreno-company-tools/tool-a:latest \
  tool-a /work/config.yml

# docker-compose コマンドで実行する場合
docker-compose run tool-a config.yml

こうやって見ると, docker-compose の方がシンプルでいい感じ.

コマンドを封じ込める Dockerfile

docker 自体のコンテナを利用する.

FROM docker
RUN apk update && apk add bash jq python curl
RUN cd /tmp && \
    curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "awscli-bundle.zip" && \
    unzip awscli-bundle.zip && \
    ./awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws
ADD script.sh /usr/local/bin/tool-a

Docker コンテナ化することで, 環境を問わず実行出来るようになるのが気持ち良いはず. 以下のように docker run する.

docker run -t -i \
  -v=/var/run/docker.sock:/var/run/docker.sock \
  -v=$(pwd):/work \
  -v=${HOME}/.aws:/root/.aws \
  -w=/work \
  oreno-company-tools/tool-a:latest \
  tool-a /work/config.yml

docker run した場合, かなりボリューミーなコマンドラインオプションとなる為, 以下のように, docker-compose を利用する.

コマンドラインオプションを封じ込める docker-compose.yml

前述の通り, docker run で実行する場合, コマンドラインオプションがボリューミーになる為, コマンドラインオプション自体は docker-compose.yml に封じ込める.

version: '3'
services:
  tool-a:
    image: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/oreno-docker-image/tool-a:latest
    container_name: tool-a
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - .:/work
      - ${HOME}/.aws:/root/.aws
    working_dir: /work
    entrypoint: /usr/local/bin/tool-a

以下のように実行する. 尚, カレントディレクトリに docker-compose.yml が存在しているとする.

docker-compose run --rm tool-a example/example.yml

実際の配布からスクリプトの実行までの流れ

f:id:inokara:20190113205757g:plain

いい感じ.

以上

社内のような狭い範囲で共用するスクリプトをどのように配布すれば良いのか考察してみた. シェルスクリプトだけではなく, Golang で書かれたワンバイナリのツールでも同じような感じで配布出来ると考えている.

Amazon S3 がシンプルで良い感じだけど, Docker イメージとして配布する方が実行する環境を汚すことなく, 環境に依存しない実行環境を提供することが出来るような気がする.

適材適所で使い分けられればなあと考えている.