GAS から HTTP GETリクエストを出したり、受け付けたりできるので、この仕組みを使って、無料で LINE ボットをつくってみる。
LINE ボットは、LINE Messaging API を利用すると簡単に作ることが可能。
出所: Messaging APIの概要 | LINE Developers
LINE ボット開発の流れは以下。
流れは以下。
詳細は Messaging APIを始めよう | LINE Developers を参照。
チャネルが作成できたら、「Messaging API設定」からチャネルアクセストークン★を発行してメモっておく。 後述のボット開発時に必要となる。
今回は、以下の機能をボットに持たせる。
まずは、新規 GAS プロジェクトを作る。 自分のプロジェクト – Apps Script から「新しいプロジェクト」で作成可能。
一つの .gs
ファイルでも良いが、ここでは以下のファイル構成で開発する。
1 2 3 |
|
話が逸れるが、2020年に入ってから GAS は V8 ランタイムをサポートし始めたので、const
とかクラス定義、アロー関数が使えるようになった。
V8 Runtime Overview | Apps Script | Google Developers
LINE で投稿された文を英訳する。LINE から Webhook で受け取った日本語文字列を英語に翻訳し、レスポンス用のJSONを返すためのクラスを作る。
翻訳には、GAS にビルトインされている LanguageApp
を使う。
Class LanguageApp | Apps Script | Google Developers
LINE Messaging APIレスポンスの認可には、上でメモったチャネルアクセストークン★が必要となる。トークンのハードコーディングを避けるため、Script properties
へ事前に設定しておく。
Script properties
は、GAS コンソールのメニュー [File] > [Project properties] > [Script properties] から設定できる。ここでは、LINE_ACCESS_TOKEN
で登録している。
class.gs
に以下を書く。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
|
LINE ボットとの会話履歴を Google Sheets に保存する。
https://sheets.new から Google Sheets を新規作成する。 作成したシートの URL から spreadsheetIDを取得する。
ttps://docs.google.com/spreadsheets/d/spreadsheetId/edit#gid=0
チャネルアクセストークンを Script properties
に設定したのと同様に、SHEET_ID
として登録する。
class.gs
に以下を追記する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
メイン処理は、LINE から日本語文を Webhook (HTTP POST) で受け取り、上述した翻訳処理、ログ処理を経て応答する。
main.gs
に書く。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
テストは省略。
開発したボットを、GAS コンソールメニューの [Publish] > [Deploy as Web app…] からデプロイする。 「Who has access to the app:」 は「Anyone, even anonymous」に設定しておく。
[Deploy] ボタンを押すと、Authorization requiredダイアログが出てくるので許可してあげる。
許可すると、「Current web app URL:」で GAS のエンドポイント URL ☆が取得できるのでメモっておく。後ほど、LINE Developers コンソールで Webhook URL にこのエンドポイントを指定する。 https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/exec 形式の URL。
以下を設定する。
詳細は ボットを作成する | LINE Developers を参照。
LINE Developersコンソールから、先に作ったチャンネルの Messaging API 設定 > Webhook 設定の Webhook URL に先程デプロイした GAS のエンドポイント URL ☆ を設定する。
次に、「Webhook の利用」を有効化する。
応答メッセージの無効化もしておく。 「応答メッセージ設定」の「編集」リンクから、「詳細設定」 > 「応答メッセージ」 をオフにしておく。
最後に、ボットの QR コードを取得し、LINE の友達に追加する。
以下の日本語入力に対して、
以下の英訳分を返してくれている。
会話のログも Google Sheets に取得できている。
]]>/neko
を作った。
Slack で /neko
と打つと、Cloud Functions にリクエストが飛び、Functions が TheCatAPI からランダムに猫画像 URL を取得するもの。
使ったもの | 用途 |
---|---|
Google Cloud Functions | バックエンド |
Python 3.7 | Functionsの実装言語 |
Serverless framework 1.40.0 | GCPへのデプロイ |
1 2 3 4 5 6 7 8 |
|
serverless.yml
を自分の GCP 環境に合わせて編集する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
まず TheCatAPI の API エンドポイントをコードの中に埋め込みたくないので、 config.json
という外部ファイルに書き出し、実行時にそこから読み込むことにする。
以下のような感じ。
1 2 3 |
|
Functions 用のコードは以下のような感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
あとは GCP にデプロイして、Slack の Slash command の設定をすれば使える。
1
|
|
Slack の Verification Token による簡易的な認証処理を追加する。
Slack command のApp設定から、Basic Information > App Credentials > Verification Token からトークンを取得して、config.json
に書く。
1 2 3 4 |
|
以下のような処理を追加し、認証処理とエラーハンドリング処理を追加する。
とりあえず意図しないリクエストがバックエンド (Functions) にきたら、例外を投げる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
メイン処理側では、例外を補足したら、それに応じたエラーを返すように変更する。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
前回も述べたが、 Slack command は 3000 ms (3秒) 以内に応答しないとタイムアウトになってしまう。
TheCatAPI のような外部 API に依存している場合、3 秒以内のレスポンスを保証できない可能性が高くなる。 そこで、バックエンドの Functions がリクエストを受けたら即時にレスポンスを返し、スレッドにより非同期で応答する。 Slack としても、そのような仕組みを支援するためにレスポンス用 URL を付与して、バックエンド側にリクエストを投げてくれる。
以下のようなイメージ。
スレッド処理のため、メイン処理を関数化し、レスポンス用 URL へ返答するよう書き換える。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
最終的には以下のような感じになる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
|
Slack commands は slack 上で /command arguments
形式で入力すると何かしらの応答を返す仕組み。/
から始まるのでSlack Slash command とも呼ばれるようだ。
詳細は公式 API ページを参照: Slash Commands | Slack
過去につくった Slack Bot が動かなくなったので、GCP を利用して作り直そうというのが背景。
クラウドへのデプロイについては serverless framework を利用した。
今回は、slack で /ping
というコマンドを実行したら、pong
と返すような slack command を作る。
できあがりは以下のような感じ。
serverless framework のインストール方法は serverless framework による AWS Lambda ローカル開発 – momota.txt を参照。
今回は、AWS Lambda (Javascript) ではなく GCP Cloud Functions (Python) を使う。
事前に GCP のクレデンシャル設定が必要となる。
~/.gcloud/keyfile.json
などここでは ping
という名前でサービス (プロジェクトのようなもの) を作成する。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
作成したサービス名と同名のディレクトリが作成されるので、移動する。
1
|
|
以下のファイルが自動生成されている。
1 2 3 4 5 6 7 8 |
|
プロジェクトディレクトリで npm install
する。
1
|
|
serverless.yml
を編集する。
project
フィールドにGCP プロジェクト ID の指定するのと、credentials
フィールドにcredentials ファイルの相対パスを指定する。
functions
以下の memorySize, timeout, labels はお好みで設定する。
handler
フィールドで指定している ping が後述する Python コードの関数名になっており、Cloud Functions 起動時に当該関数が呼び出される。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
Slack から ping を受けたら pong を返す Python コードを書く。
Slack command が実行されとき Slack から送信されるリクエストは以下のようなフォーマットになっている。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
これに対して、以下のような Json フォーマットでレスポンスを返す必要がある。
1 2 3 4 5 6 7 8 9 |
|
main.py
を編集する。以下のようなコードになる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Flask ライブラリに依存しているので、requirements.txt
を作る。
1
|
|
serverless deploy
により、GCS にソースコードがアップロードされ、Cloud Functions が Python 3.7 で起動する。
これはマネジメントコンソールからも確認できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Slack API: Applications | Slack から Create New App
ボタンをクリックしコマンドを作成する。
設定のやり方はこのあたりを参考にしたら良いと思う。: Slackのコマンドを作ろう!! – Qiita
command 作成時の Request URL
に作成した Cloud Functions のエンドポイント https://us-central1-YOUR-GCP-PROJECT-ID.cloudfunctions.net/ping を指定する。
Slack の設定が終わると、Slack から使えるようになる。
Functions は初回起動時に少し時間がかかる。 Slack command は 3000 ms (3秒) 以内に応答しないとタイムアウトになってしまう。 タイムアウト時は Slack command を再実行してみたら良い。
]]>こんな感じで便利。
robbyrussell/oh-my-zsh を導入している前提。
oh-my-zsh の導入に関しては、こちらの記事を参照: zsh をログインシェルにしてワーク・ライフ・バランスを改善する (oh-my-zsh) – momota.txt
今回利用するカスタムスクリプトは ~/.oh-my-zsh/custom/
以下に置けばログイン時にロードしてくれる。したがって、公式に書いてある source incr*.zsh
を .zshrc
へ書く必要はない。
スクリプト名にバージョン名が入っているのが気持ち悪かったので、incremental_completion_for_zsh.zsh
へ修正した。
1 2 3 4 5 |
|
サジェストされるコマンド文字の色を控えめにしたかったので、以下の修正を加えた。 (グリーンからグレーへ変更)
1 2 3 4 5 6 7 8 9 |
|
サイバーエージェントとk8s
レガシーシステムのマイグレーションもスタート地点はここから。実行環境込みのアプリケーションをSystemdに置き換えるイメージ
$ kubectl apply -f manifest.yaml
1 2 3 4 5 6 7 8 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
1 2 3 4 5 6 7 8 |
|
GCPでは、徹底的な防御がデフォルトでON
コンテナのセキュリティとは
コンテナセキュリティの脅威とリスク
インフラストラクチャセキュリティ | ソフトウェアサプライチェーン | ランタイムセキュリティ |
---|---|---|
権限昇格 | パッチ適用漏れによる脆弱性 | DDoS |
機密情報の漏洩 | サプライチェーンに聞いする脆弱性 | Node への不正アクセス |
Kubernetes API の漏洩 | 共通ライブラリのゼロデイ脆弱性 | Container escape |
必要以上の権限を持つユーザ | Flood event pipline |
Google Cloud Japan 篠原 一徳氏、村上 大河氏
3つのポイント
株式会社フリークアウト 西口 次郎 氏
RED: Freakout DSP
cloud.google.com/neg
に { "ingress": true }
を指定するbeta.cloud.google.com/backend-configs
2008年にGithub社創業
上記の考え方なので、以下も大事
Cloud Native
Cloud Native Ecosystem
Cloud Nativeに適したアーキテクチャ? 大規模な開発に適したアーキテクチャ?
広告デザイン業務: デザインツール
どのフォントが見やすいかユーザ調査(3種)。一般的にはスマートグラスで明朝体は字が潰れるので避けられる。
ブランディングはフォントで決まる
Hololensへインストール
毎回illustratorを起動し、修正も大変だった→TypeSquare APIの利用
平山 涼也さん
ある程度全社的な判断や横断的な視点の組織が必要となる
どういうメンバーで挑むか
開発初期から運営・運用が重要という想定
例えば、ロジックは一箇所に集約すべし、など
1 2 3 |
|
Q: 開発体制・人数は?
A: 秘密(人事から止められている)。スタッフロールから想像して。
Q: 修正の影響範囲の特定の仕方は?
A: あまりよくない答えだが、個別・経験値に依存している。
Q: チケット登録がなかなか浸透しない理由は?
A: 開発者がチケット登録するまでもないと思っちゃう。リファクタリングのつもりで軽く対応しちゃうときにバグが埋め込まれてしまう。油断、おごりがある。
Q: 運用以降が本番、というところのモチベーション維持に関しては?
A: 実際、飽きたと言って抜けちゃう人もいる。チーム内で異動させたりする。
小野寺 民也さん
そもそも量子とは
午後は打ち合わせがあったので午前中までの参加だった。
]]>GCPでk8sを使うには以下のパターンがある
$ gcloud container clusters create MY_CLUSTER
kubectl create -f ./k8s
kubectl port-forward svc/nginx 9999:80
curl http://127.0.0.1:9999/api/prom/api/v1/query?query=up
Kernel module / sysdig libraries
Falcoを実行するとDKMSによってmoduleがbuild&installされる
lsmod | grep falco
falco.yaml
の設定デフォルトで冗長機能がない
長期保管: Third party adapterの利用
上記を応答時間を犠牲にすることなく実現
Querier
Ruler: 通知用
2019年1月時点ではGCSのみ対応
Serverless Framework を使うことにより、FaaS (AWS Lambda, GCP Cloud Functions, Azure functions, など) の開発をローカルで実施できる。 ローカル環境で自分の好きなエディタ・IDEで開発やテストが可能になるし、デプロイも容易になる。
AWS には AWS SAM もあるが、他のクラウドプロバイダでも開発物やノウハウが使い回せることが期待できるので、3rd パーティ製の Serverless Framework を選ぶ。
本稿では、Serverless Framework の導入と、Hello Worldアプリ (AWS Lambda) のデプロイについて書く。
1 2 3 4 5 |
|
まず Node.js (v6.5.0以降) と npm をインストールする。
1 2 3 4 5 6 7 8 9 |
|
npm で serverless framework をインストールする。
1 2 3 |
|
1 2 3 4 5 6 7 |
|
まず、作業ディレクトリの作成と、package.json
を作成する。
1 2 |
|
いくつかのライブラリをインストールする。
1
|
|
アプリケーションを index.js
に書く。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
これはルートパス /
にアクセスがあった場合に、 { id: '00001', message: 'Hello World!' }
を返す単純なアプリ。
これをデプロイするため、以下の serverless.yml
を作成する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
関数をデプロイする。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
数分後にデプロイが完了し、endpoints
の情報が出力される。
この URL へアクセスし、動作確認する。
1 2 |
|
アプリケーションで定義した JSON が返ってくる。
Kong を利用して、各 API に対して上記のようなアクセスを制御する。
aaa
は API a に対してアクセスできる。しかし、API b にはアクセスできない。bbb
は API b に対してアクセスできる。しかし、API a にはアクセスできない。Kong のプラグイン key-auth
と acl
により実装する。
各設定をまとめると以下。
ユーザ | service | route (kong path) | api key | consumer | group |
---|---|---|---|---|---|
aaa | aaa-api | /aaa | aaaaaaaaa | aaa | aaa-group |
bbb | bbb-api | /bbb | bbbbbbbbb | bbb | bbb-group |
API a の service を定義する。
Service 名は aaa-api
, 実体は mockbin.org。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
API b の service を定義する。
Service 名は bbb-api
, 実体は www.gaitameonline.com。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
API a に route を設定する。
Consumer aaa
には、Kong の /aaa
という PATH を公開したいので、paths[]=/aaa
を定義する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
API b にも同様に route を設定する。
Consumer bbb
に、Kong の /bbb
という PATHを公開する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
ここまでで、以下のようなプロキシ設定ができた
アクセス先 | プロキシ先 |
---|---|
http://localhost:8000/aaa | http://mockbin.org |
http://localhost:8000/bbb | https://www.gaitameonline.com/rateaj/getrate |
key-auth プラグインを有効化し、API キーがない場合はアクセス拒否する。
各 service に対して有効化する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
|
API キーがないとアクセスできないことを検証する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
Consumer aaa
と bbb
を作成する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
各 Consumer に API キーを発行する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
以上の設定で、API キーがあれば API a, API b にはアクセスできるようになった。
しかし、Consumer aaa
の API キーで、API a および API b の双方にアクセスできる。
Consumer bbb
も双方の API にアクセスできる。
アクセス制御するために、ACL プラグインを利用する。
acl プラグインを利用することで、service や route 単位のアクセス制御が可能になる。
Consumer をグループに所属させ、グループ単位にアクセス許可する (config.whitelist
に許可するグループを定義する) か、アクセス拒否する(config.blacklist
に拒否するグループを定義する)。
ここでは、consumer aaa
をグループ aaa-group
へ、consumer bbb
を bbb-group
へ所属させ、各サービスへ許可設定をする。
まずは、各サービスに対して、acl プラグインを有効化する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
|
各 consumer にグループを設定する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
Consumer aaa
が API a にはアクセスでき、API b にはアクセスできないことを検証する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
1 2 3 4 5 6 7 8 9 10 11 |
|
アクセス制御が効いていることを確認できた。
最近はあまり流行っていないらしく、Web 上の記事が古かったので、使い方に関するメモ。といってもほぼチュートリアル通り。
古いなと感じたのは、たとえば、マイクロサービスの流行りを受けてか、api という概念が service に置き換えられている感じだった。
Docker や Vagrant など様々な形で提供されているので、略。
kong に API を追加するためには、まず Service を追加する必要がある。 Service は、Kong が管理する上流の API およびマイクロサービスを参照するための名前。
ここでは、Mockbin API を利用する。 Mockbin は「echo」タイプの Web サービスで、リクエストをレスポンスとして返すサービス。
Service には、route を追加する必要がある。 Route は、Kongにリクエストが到達したあとに、バックエンドの service 郡に対するリクエスト送信方法を指定する。1つの service に複数の route を含めることができる。
Service と route を設定したら、Kong 経由の API リクエストが可能になる。
これらの設定は、RESTful Admin API を利用する。
(デフォルトでは、TCP ポート :8001
で公開されている)
Mockbin API を指す、service example-service
を追加する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
これにより、Kong は service を認識し、リクエストをプロキシできる準備が整った。
Kong はデフォルトで、TCP ポート :8000
で API 利用者のリクエストを受け付ける。
HTTP レスポンス 200 OK
が返ってきており、Kong 経由で Mockbin のレスポンスが返っている。
Kong は、HTTP ヘッダ Host: <given host>
でどうフォワーディングするかを認識する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
登録した service の一覧は、http://localhost:8001/services/ に GET リクエストを投げる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Kong はプラグインにより拡張できる。 ここでは、key-auth plugin を service に追加する。 これまでの設定では、すべてのリクエストが上流サービスに流れる。 key-auth プラグインを設定することにより、適切な API キーを持つリクエストのみがプロキシされる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
key-auth プラグインは、config.key_names
パラメータを受け付ける。
デフォルトは ['apikey']
になる。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
必要な apikey
ヘッダーまたはパラメータを指定していないため、応答は401 Unauthorized になる。
Kong インスタンスに consumer (APIの利用者) を追加する方法を学習します。 Consumer は API を使用する個人に関連付けられ、追跡、アクセス管理などに使用できる。
Jason
という名のユーザを追加する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Jason
に対して、キーを作成する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Kong の設定も RESTful API で確認できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
|
動作の軽量化もちょっとは期待できるかも。 (比較計測はしていない)
以下は、関連記事。
ソフトウェア | バージョン |
---|---|
OS | Windows 10 Pro 1709 |
ブラウザ | Google Chrome 69.0.3497.100 |
ChromeDriver | 2.39.562718 |
ruby | 2.5.1p57 |
gem selenium-webdriver | (3.14.1, 3.12.0) |
Ruby と gem はインストールされているものとする。
Chrome のバージョン59以降からヘッドレスモードを搭載している。 Chrome をインストールしていない場合は、インストールする。
動作確認はコマンドライン (Powershell or コマンドプロンプト) から可能で、以下のように動けば OK。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Proxy 環境下にいる場合は、--proxy-server
や --proxy-auth
オプションで指定してあげればよい。
1
|
|
詳細は ヘッドレス Chrome ことはじめ | Web | Google Developers のあたりを参照。
Selenium WebDriver は Selenium から Web ブラウザをコントロールするライブラリ群。 各ブラウザ向けに実装されていて、ChromeDriver は Chrome 用の WebDriver。
以下から入手し、PATHを通す。(もしくは通っているところに置く)
コンソールからバージョンが表示できれば PATH 設定の確認になる。
1 2 |
|
サンプルとして、本ブログのいくつかのページのスクリーンショットを取得する。 http://momota.github.io/blog/page/2/ ~ http://momota.github.io/blog/page/4/ のスクリーンショットを取得してみる。
Headless モードといっても特段難しいことはなく、以下のように Webdriver にオプションしてあげるだけでよい。
1 2 3 4 5 6 |
|
Proxy の設定が必要な場合は、以下のようにオプションで指定する。
環境変数 ENV['http_proxy']
に設定してもだめなので注意。
1 2 3 4 5 6 7 8 |
|
スクリプトとしては以下のような感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
普通に ruby script.rb
で実行すると、スクリーンショット 実行ディレクトリ/screeshot/headless_i.png
が出力される。
1 2 3 4 5 6 7 8 9 10 11 |
|
Python のバージョンは 3.6。
Flask アプリのディレクトリ構成は以下。
1 2 3 4 5 |
|
mattermostbot.py
: ボット本体log/
: ログ保存用のディレクトリmattermost.py
は簡易的なオウム返しするボットで以下のようなスクリプト。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
|
コンテナにインストールする必要のある Python パッケージ を requirements.txt
に書き出す。ようは pip
でインストールやつを列挙する。
1
|
|
手で作らなくても、すでに Flask アプリを動かしている環境があれば、以下のコマンドで出力できる。
1
|
|
Docker イメージを生成するため、以下のような Dockerfile
を作成する。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
プロキシ環境下でビルドする場合は、以下のようにコンテナ内の環境変数を設定してあげれば良い。
追記する場所は、RUN pip install -r requirements.txt
より前。
1 2 3 4 5 6 7 8 9 |
|
以下のコマンドで Docker イメージをビルドする。
1
|
|
できたイメージは以下で確認できる。
1
|
|
1
|
|
起動状態などの詳細は以下で確認できる。
1
|
|
curl
や POSTMAN などを使って HTTP POST リクエストを投げて確認する。
1 2 3 4 5 6 |
|
このスクリプトからHTTP GETリクエストを出したり、受け付けたりできる。
今回は、この GAS を使って、無料の Web クローラをサーバレスでつくってみる。
API は https://www.gaitameonline.com/rateaj/getrate を利用する。 ここへ HTTP GET すると以下のような JSON フォーマットが返ってくる。 (整形済み)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
JSON の quotes は各通貨ペアの配列になっており、各要素に high, low, … などのフィールドがある構造になっている。
robots.txt には特に言及されていないが、非常識なアクセスはしないように注意。
Apps Script のメニューから + 新規スクリプト
をクリックすると、新規プロジェクトが立ち上がる。
プロジェクト名やスクリプト名は適当に変更する。 (デフォルト Code.gs
)
GAS で API をたたく処理は以下のように書ける。
1 2 3 4 5 6 7 8 9 10 11 |
|
UrlFetchApp.fetch(url)
で API の URL をたたきにいける。
fx.date = now
で、取得した JSON に取得日時フィールド date
を足している。
上記をコピペして実行する (▶ボタンを押す) と初回実行時には以下のような確認ダイアログがでるので Review Permissions
を押して許可する。
その後、Choose an account画面で自分のアカウントを選ぶと、確認画面 YOUR-PROJECT-NAME wants to access your Google Account
が出てくるので ALLOW
ボタンを押す。そうすると実行できる。
Logger.log(fx)
部分でログ出力しているので、メニュー View
> Logs
からログ出力できていることが確認できる。
ログは以下のように出力される。
1 2 |
|
取得した為替レートを以下のように Google sheetsに出力する。
シートの 1 行目はヘッダ、列の定義は以下。通貨ペア種別すべての Ask や Bid などを取得したタイミングごとに1行で表現する。
1
|
|
まずは、出力先にあたる Google sheets を新規作成し、その URL をコピーする。
個別の URL をコードに埋め込みたくないので、Script properties
に値をセットしてそれをコードの中から利用する。
GAS のメニュー File
> Project properties
から Script properties
タブへ移動する。
+ Add row
のリンクから行をエントリーする。
Property
に SHEET_URL、Value
に先程コピーした Google sheets の URLを登録する。
登録するURL は https://docs.google.com/spreadsheets/d/xxxxxxxxxxxxxxxxxxxxx/edit
のような形式。
上述した Script properties
から値を参照して、Sheet オブジェクトを取得する処理は以下。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
API から取得してきた JSON データをシートに出力する。
シートに対して入力するには、sheet.getRange(row, column).setValue(something)
のようにシートの行 (row) と列 (column) を指定して setValue を呼べば良い。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
上記をまとめると以下。 以下をコピペして実行する (▶ボタンを押す) と Google sheets に為替データが挿入される。 初回実行時に権限の確認ダイアログがでると思うが許可してあげる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
|
上記の処理を定期的に実行する。
時計マークのアイコンをクリックする。もしくは、メニュー Edit
> Current project's trigger
を選択する。
そうするとダイアログが出てくるので、No triggers set up. Click here to add one now.
をクリックする。
Run
にはメイン処理の scrapeExchangeToSheet
, Events
には好きな起動時間を設定できる。
ここでは1分間隔で実行するため、Time-driven : Minutes timer: Every minute
を選択する。
1分間隔で Google sheets にデータが挿入されていることが確認できる。
]]>1 2 |
|
ディレクトリ構成は以下。
1 2 3 4 5 6 |
|
mattermostbot.py
: ボット本体test_mattermostbot.py
: テストコードlog/
: ログ保存用のディレクトリmattermost の統合機能から「外向きのウェブフック」を設定する。
チャットボットは bot_name COMMAND ARGUMENT
のように呼び出す。
ここではコマンドは以下の5種類をテストすることにする。
ARGUMENT
をそのまま返すチャットボットのコード mattermostbot.py
は以下。Slack のボットとしても機能するはず。
Flask を使って HTTP POST で送られてくる JSON データを mattermost から受け取って、処理している。
bot()
メソッドがボットメイン処理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
|
以下を参考にした。
Python の Flask で作ったアプリケーションをテストする | CUBE SUGAR STORAGE
各チャットボットコマンドに対応するテストケースを以下のように書ける。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
|
テストを実行するとこんな感じになる。
1 2 3 4 5 6 |
|
日本語を扱いたいのでプラグイン kuromoji
をインストールする Dockerfile を用意する。
Dockerfile の内容は以下。
1 2 3 4 5 |
|
この Dockerfile に基づいてイメージをビルドする。
1 2 3 4 5 |
|
Install Elasticsearch with Docker | Elasticsearch Reference [6.2] | Elastic に書いてあるとおりに起動する。
1
|
|
起動を確認する。
1 2 3 |
|
Elasticsearch の正常稼働を REST APIから確認する。 Ubuntu (WSL) から curl
を使う。
health
が green
なので問題ない。
1 2 3 4 |
|
Windows側で確認する場合は、curl
の代わりに PowerShell Invoke-WebRequest
コマンドで確認できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
index を作ってみる。 index は RDB のテーブルやビューにあたる。
PUT メソッドを使って customer
という index を作る。
pretty
は JSON を pretty-print (pretty-print) してくれる。 jq
みたいに整形してくれる。
1 2 3 4 5 6 |
|
index が増えていることが確認できる。
1 2 3 4 |
|
document を追加する。 RDB のレコードみたいなもの。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
PowerShell バージョンは以下。
1 2 3 4 5 |
|
document の確認。
1 2 3 4 5 6 7 8 9 10 11 |
|
pip で Python Elasticsearch Client をインストールする。
1
|
|
質問, 回答
みたいな FAQ をためている CSV ファイルを Elasticsearch へインポートする。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
BitLocker は OS ログイン前に C ドライブの暗号化を解除しろ、とパスワード入力を求めてくる。 ただし、その後、OS ログインしても、C ドライブ以外 (たとえば、D ドライブ) は暗号化されたままとなっており、いちいち当該ドライブへアクセスしてパスワード入力して暗号化を解除する必要があった。 また、暗号化解除前に D ドライブ上のファイルへアクセスするとエラーが起きてしまい、大変うざったい。
そこで、OS ログイン時に自動的に C ドライブ以外のディスク暗号化解除するために PowerShell とバッチを書いてスタートアッププログラムに登録した話を書く。
セキュリティクラスタには怒られるのかもしれないが、OS に管理者権限ユーザでログインできている時点でもういろいろ見れて当たり前やろ、という思想。
全体の流れは以下。
ここでは D ドライブの BitLocker 解除するスクリプト C:\PATH-YOU-WANT\unlock-bitLocker.ps1
を書く。
1 2 3 4 |
|
複数のドライブがある場合は以下。
1 2 3 4 5 6 |
|
上述の PowerShell スクリプトを管理者権限で実行し、かつ、スタートアッププログラムに登録するために、上記の PowerShell を呼び出すバッチファイル C:\PATH-YOU-WANT\unlock-bitLocker.cmd
を書いてあげる。
PowerShell を直接登録したかったのだが、調査力が足りず変な構成になった…
もしくは、これくらいなら PowerShell スクリプトはいらず、バッチスクリプトだけでもよかったかもしれない。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
unlock-bitLocker.cmd
をスタートアッププログラムに登録すると、実行時に管理者権限で実行するかという確認ダイアログがでて毎回うざったい。
そこで、いったん上記のバッチスクリプトをタスクスケジューラに管理者権限実行のタスクとして登録してそのタスクをスタートアッププログラムから起動する。
Windows キー + r
: ファイル名を指定して実行を起動taskschd.msc
を入力: タスクスケジューラが開くunlock_bitlocker.cmd
を起動するタスクを作成するC:\PATH-YOU-WANT\unlock-bitLocker.cmd
を指定1 2 3 4 5 6 7 8 9 |
|
Windows キー + r
: ファイル名を指定して実行を起動shell:startup
を入力: スタートアップのフォルダが開くtrigger_unlock-bitLocker.cmd
のショートカットをスタートアップフォルダの中に作成以上で、OS ログイン後に D ドライブの BitLocker を解除できる。
BitLocker を有効にしていると、初回起動時に NumLock が有効になっているのを無効化したいんだが、だれか方法を教えてほしい。
]]>// 結構な文量になってしまった…
大きく、2つのアプローチがある。
まあ、地道に、計測→問題点の特定→修正→計測… のサイクルを回すしかない。
バッファプールサイズ innodb_buffer_pool_size
innodb_buffer_pool_size
は InnoDB のデータとインデックスをキャッシュするメモリ上の領域。可能な限り大きくすることが基本方針。innodb_buffer_pool_size
はメインメモリの 70-80% 程度を割り当てる。データとインデックスの両方をキャッシュする。(デフォルトは128MB)バッファプールインスタンス innodb_buffer_pool_instances
innodb_buffer_pool_size
が大きく、mutex競合がオーバヘッドとなっている場合は、2以上に設定innodb_buffer_pool_size
は N * innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances
に等しいサイズにする必要あり。1 2 3 4 5 6 7 8 9 |
|
innoDB_page_size
データファイルアクセスに OSキャッシュを無駄に消費しないよう innodb_flush_method
を O_DIRECT
にする。
O_DIRECT
にすると、OSのDirect I/O機能を利用し、OSのキャッシュをバイパスする。MySQL は自前のキャッシュ機構があるので、OSキャッシュは冗長なので、バイパスしたほうがよい。O_DIRECT
にしたほうがオーバヘッドが下がるinnodb_log_file_size
innodb_buffer_pool_size
の25%~100%。デフォルト45MB。最大リカバリ時間に影響するので考慮しつつ大きく設定する。innodb_log_buffer_size
innodb_flush_log_at_trx_commit
innodb_flush_log_log_at_trx_commit
が 1 の時、ログバッファはトランザクションがコミットされるたびにディスク上のログファイルに書き出され、データの整合性を最大限保つ。しかし、これはパフォーマンスへの影響がある。この値を2にすると、ログバッファはトランザクションのコミットごとにOSのファイルキャッシュへ書き出される。これにより、ACIDを意識しないのであればパフ
ォーマンスを最適化・高速化できるが、OSのクラッシュ時には数秒分のトランザクションが消えてしまう可能innodb_file_per_table
Double Write Buffer
innodb_doublewrite = ON
(デフォルト設定) が推奨innodb_thread_concurrency
で同時実行スレッド数を調整する。
InnoDB compression (圧縮機能)
innodb_file_per_table
を有効化することinnodb_file_format
が Barracuda であることCREATE TABLE
もしくは ALTER TABLE
で ROW_FORMAT=COMPRESSED
か KEY_BLOCK_SIZE
を指定するinnodb_io_capacity
innodb_read_io_threads
, innodb_write_io_threads
max_connections
thread_cache_size
max_connections / 3
8 + (max_connections / 100)
により自動計算。sort_buffer_size
query_cache_size
query_cache_type
autocommit
は高負荷なのでOFFが推奨。
Read-Ahead
再起動時のウォームアップ運用
適切なSQLを使う (クエリ最適化)
SHOW FULL PROCESSLIST
で現在実行中の時間がかかっているクエリを特定するテーブルの最適化
適切な粒度でcommitする
レプリケーションを利用した負荷分散
コネクションプーリングする
Innodb compression
推測するな、計測せよ。
設定を変えたり、プログラムを変えたりしても、効果を測れないと意味がない。
INFORMATION_SCHEMA
INNODB_CMP*
: 圧縮の状況INNODB_TRX
, INNODB_LOCKS*
: ロック状況INNODB_SYS_*
: システムテーブル (メタデータ)INNODB_BUFFER_*
: バッファプールSHOW ENGINE INNODB STATUS
top
風に MySQL のステータスを表示するツール公式サイトは以下。
前提知識としては、以下。知っていたほうが理解が早い。
公式から引用すると、Ansible は simple IT automation engine。
Ansible is a radically simple IT automation engine that automates cloud provisioning, configuration management, application deployment, intra-service orchestration, and many other IT needs.
—– How Ansible Works より
以下は、Ansible の動作イメージ。(https://sysadmincasts.com/episodes/46-configuration-management-with-ansible-part-3-4 より引用)
/etc
以下の設定)
公式サイトの Use case を直訳すると、以下。
- provisioning (Bootstrapping と呼ぶほうが正しいかも)
- ベアメタルサーバやVMに対する、PXEブート (遠隔電源操作), キックスタート (linux の自動インストール)
- VM (クラウドインスタンス) に対する、テンプレートからの作成
- configuration management
- コンフィグファイルの中央管理
- application deployment
- Ansible でアプリケーションを定義しデプロイすることで、開発環境から本番環境までのアプリケーション全体のライフサイクルを効果的に管理できる
- continuous delivery
- CI/CD のパイプラインはたくさんのチームから依頼を引き受けることになる。だれもが使えるシンプルなAnsible を使うことで適切にアプリケーションのデプロイ管理ができる
- security & compliance
- Ansible でセキュリティポリシを定義することで、サイト全体のセキュリティポリシのスキャンと修復が可能になる。
- orchestration
- 管理対象のコンフィグは多種多様に存在し、かつ、それぞれが相互に作用している。Ansible は、この複雑で混沌とした中に秩序をもたらす。
仕事ではあまり OS を扱うことは少なく、以下のようなレイヤの低いやつを raw モジュールを 駆使して構成変更したり情報取得したりしている。
Installation – Ansible Documentation を参照
ansile を単体実行するコマンド書式は以下。
1
|
|
オプション | 意味 |
---|---|
-f | 実行多重度。デフォルトは5 (ansible.cfg で規定) |
-m | モジュール名 |
-a | モジュール引数 |
以下はローカルで動くモジュールの一部を紹介。
モジュール | 機能 |
---|---|
ping | その名の通り ping |
shell | コマンドを引数に渡して shell 実行可能 |
file | ファイルのパーミション設定とか、ディレクトリ作成とか |
template | Control Machine のテンプレートファイル (テンプレートエンジンは jinja2 ) を Managed Node に配布 |
service | init system のサービスを制御 |
sysctrl | カーネルパラメータの操作 |
raw | ssh でナマの文字列をそのまま流し込む |
インターネットに接続していれば、以下も有用。
モジュール | 機能 |
---|---|
yum | yum によるソフトウェアパッケージ管理 |
get_url | HTTP でのダウンロード (curl, wget 的な) |
git | git リポジトリからの clone |
バージョンが 2 系からJunos とか Cisco, ESXi 用のモジュールもある。
<host-pattern>
でホストを指定する。
all とすると、/etc/ansible/hosts
で定義しているすべてのホストが対象となる。
以下は ping
モジュールを利用したコマンド。
localhost に ping する ansible コマンド。
-m
オプションのあとに ping
モジュールを指定する。
1 2 3 4 5 |
|
以下は、shell
モジュールを利用したコマンド。
-a
オプションのあとにモジュール引数を渡す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
ただし、実際には ansible
コマンドを使うことはめったにない。
複数のノードに対してタスクを実行したり、複雑なタスクを実行する場合は、 Inventory ファイルや Playbook ファイルを利用する。
Ansible の主なファイルは以下。
/etc/ansible/ansible.cfg
Inventory ファイルは、ansible 用の hosts ファイル。 ホストやグルーピングの設定、変数などの定義が可能。 ホストや IP アドレスはレンジでの指定も可能。
以下は、デフォルト設定 /etc/ansible/hosts
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
Playbook はタスクをまとめて、1つのファイルに記述したもの。 実行順序や依存関係、変数を利用した処理、ループ処理などが表現できる。
Playbookの基本的なフォーマットは以下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
ansible ではホストに対する処理をタスクという単位で管理する。 通常、1つのタスクには1つのモジュールを指定する。
1 2 |
|
name は description なので省略可能だが、メンテナンス性や playbook 実行時にわかりやすいので絶対書いたほうが良い。
name は日本語でも記載可能。 (文字コードは注意)
ハンドラは、特定のタスクの実行後に、予め指定した処理を実行するための仕組み。 以下のように記述する。
1 2 3 4 5 6 7 8 |
|
この場合、「be sure httpd is installed」というタスクが実行されると、続いて「notify」で指定された「restart httpd」というハンドラが実行される。
with_items
で列挙した項目に対してループ処理が可能。
リモートのコマンド結果 (標準出力)に対して、一行ずつ処理するタスクが以下。
1 2 3 4 5 6 7 |
|
こんな感じで直接リストを書いてもOK。
1 2 3 4 5 6 7 |
|
まずはインベントリファイル sample_hosts
を作成する
“fujiko” グループに所属しているホストのリスト (計3台分) を記述している。
1 2 3 4 |
|
次にplaybook ファイル sample_playbook.yml
を作成する。
計 3 つのタスクを記述している。
register: <変数名1>
という書式でタスク実行結果を変数に保存する。 この変数を Registered Variable と呼ぶ。
debug: var=<変数名1>/stdout_lines
により、変数に保存したタスク実行結果 (の標準出力) を表示している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
playbook の実行前に syntax check (構文の確認)をする。
1 2 3 |
|
次に playbook を dry-run。 実行する前に何が変更されるか、特に、実行時に消えてしまうリソースや入れ替わるリソースを知りたい場合に有効。
1 2 |
|
Playbook を実行する。--step
オプションを付けると、タスク単位にステップ実行もできる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
|
playbook は role という単位で分割可能。再利用性が高くなり、1 つ 1 つの playbook の 見通しも良くなるなるので、相互に関係のないタスクは分離していくほうが望ましい。
大規模な環境用に、Best practices が示されているので、ご参考に。
Playbook 実行結果に「GATHERING FACTS」と出力されている。 これは対象サーバから情報を収集する処理。たとえば、リモートサーバのIPアドレスや OS名などのシステム情報を、Playbook 中で変数として扱うことができる。
次のように setup
モジュールにより、どんな変数が利用可能かを確認することができる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
|
たとえば、IPアドレスは {{ ansible_eth0["ipv4"]["address"] }}
のように、Playbook の中で変数として
扱うことができる。
その他、facter
や ohai
がリモートホストにインストールされていればそれらも利用可能。
facts よりも詳細な情報が取得できる。
この facts は、いまのところリモートホストが Linux でのみ動作する。 リモートホストが windows やネットワーク機器の場合は以下のように無効化できる。
1 2 |
|
また、システム情報を利用しない場合も無効化することで実行時間短縮が図れる。
t-wada さんのエントリ Mac の開発環境構築を自動化する (2015 年初旬編) – t-wadaのブログ変更する を見れば事足りると思われるので、本稿は自分用のメモ(t-wada さんのを少しだけカスタマイズ & 補足)。
実行環境は以下。
what | version |
---|---|
laptop | MacBook Pro (Retina 13-inch, Early 2015) |
OS | OS X El Capitan 10.11.6 |
ansible | 2.1.1.0 |
ansible では、コントローラ (Control Machine) から SSH 越しで管理対象ノード (Managed Node) を操作する。 今回は Control Machine も Managed Node も同一マシン (Macbook) なので、localhost に SSH できるようにする。
まず SSH の許可設定。 Mac で「システム環境設定」 > 「共有」 > 「リモートログイン」にチェック。
次にパスなしログインするために公開鍵を設定する。 こちらでも紹介したとおり、以下のようにする。
1 2 3 4 5 6 7 8 9 |
|
Homebrew をインストールするために必要なので、App Store から XCode をインストールする。 XCode インストール後、ライセンス同意する。
1
|
|
ライセンス規約みたいな文章がつらつらと出てくるので、最後に「agree」と入力する。
XCode のコマンドラインツールもインストールする。
1
|
|
Homebrew は Mac 用のパッケージマネージャ (yum とか apt 的なやつ。 Homebrew って、ホームブリューと読んでいるけどホームブルーのほうが正しい発音ぽい)。
公式サイトの案内に従い、以下のワンライナーで Homebrew をインストールする。
1
|
|
上記ワンライナーでインストールするとたぶん最新版がインストールされるが、インストール後 brew doctor
で古いと出力されたらアップデートする。
1 2 |
|
Ansible に必要な python はすでに 2.7 系がプリインストールされていたので、 そのまま Homebrew で Ansible をインストールする。
1 2 |
|
前回の Ansible でノート PC をセットアップ で作った仕組みにのせる。
t-wada さんの場合、1 枚の Playbook に変数やタスクを記述していたが、ありものは活用したいという思いがあり。
今回は以下のようなアレンジをした。
vars/common.yml
に切り出す1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
common/
以下の role を利用する
mac/
以下に切り出す
hosts
に mac 用グループ [mac]
を作る1 2 |
|
ディレクトリ構造は以下のようになった。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
できあがった Playbook は Github にあげた。 momota/laptop-build
tee
とかを使って Playbook の実行出力結果をファイルに保存しようと思ったが、ansible のログ機能を使った。
ansible.cfg
に以下を記述。
1 2 |
|
mac の場合、/etc/ansible/ansible.cfg
がなかった (ディレクトリごとない) ので、~/.ansible.cfg
を作成した。
absible-playbook コマンドで実行する。
1 2 3 4 5 6 |
|
HOMEBREW_CASK_OPTS="--appdir=/Applications"
をつけないと、アプリケーションによって /Applications
だったり、 ~/Applications
だったりにシンボリックリンクリンクが作られてしまうとのこと。
ログインシェルを zsh に変更するタスクで sudo
するので、-K
オプション付き。
Playbook をコピペして実行したら、shell モジュールで brew
を呼んでいるタスクから
command not found
エラーが返ってきた。
フルパスで指定し直す。
/vars/common.yml
にインストールしたい cask パッケージ名を定義するが、パッケージ名を謝って途中で処理がこけた。
もちろんググっても良いと思うが、事前に以下のコマンドなどで調べるとよさそう。
1
|
|
Homebrew cask でパッケージインストール途中で処理が止まることがあった。(2, 3回)
どんなに待っても止まったままなので、 Ctrl-c
で中断する。
ansible-playbook コマンドに -vvv
オプションなどを付けるも、原因はよく分からず。
たぶん、ansible ではなく brew 側に原因がありそう。
インストール処理で止まっているパッケージは、ansible で表示されているパッケージの、vars/common.yml
での変数定義上の次のパッケージ。
途中で止まっているパッケージもインストール一覧に出力される。
1 2 |
|
リストには表示されるものの、中途半端にインストールされていそうなので、
brew
コマンドでインストールし直して Playbook を再実行する。
1 2 3 4 5 6 7 |
|
なにも考えずに re-run できるのはうれしい。 (これが冪等性のパワーか)
]]>