2023/12/14

Terraform コードのテスト方法

詳解 Terraform 第3版

2023年11月に「詳解 Terraform 第3版」の日本語版がオライリーから発売された。

https://www.oreilly.co.jp/books/9784814400522/

詳解 Terraform の目次

  • 1章 なぜ Terraform を使うのか
  • 2章 Terraform をはじめよう
  • 3章 Terraform ステートを管理する
  • 4章 モジュールで再利用可能なインフラを作る
  • 5章 Terraform を使うためのヒントとコツ:ループ、条件文機、デプロイ、その他つまずきポイント
  • 6章 シークレットを管理する
  • 7章 複数のプロバイダを使う
  • 8章 本番レベルの Terraform コード
  • 9章 Terraform のコードをテストする
  • 10章 チームで Terraform を使う

「9章 Terraform のコードをテストする」が気になったので購入し、気になるところをメモした。

Terraform コードのテスト手法

本書の中ではテスト手法を以下のように区分している。

  1. 静的解析
  2. プランテスト
  3. サーバテスト
  4. ユニットテスト
  5. 結合テスト
  6. E2Eテスト

リストの下に行くにつれて実装・実行コストが増えるが、Terraform コードの動作確認における確からしさが上がっていく。

実際には特定の区分のみ用いるのではなく、静的解析 + プランテスト + ユニットテスト + E2Eテストなどのように組み合わせて使う。

結論

やはり銀の弾丸はない。自分たちの身の丈、運用、サービスレベルにあったテスト手法を選択することになる。

テスト手法の組み合わせ、各テスト手法にかけるコスト比重、導入順序を検討し、サービスの成長に合わせて変えていくことになる。

静的解析はコストが非常に少ないのでとりあえず導入してみるでも良さそう

以下はそれぞれの手法の概要です。

静的解析

代表的なツール

  • terraform validate
  • tfsec
  • tflint
  • Terrascan

静的解析ツールの強み

  • 動作が高速
  • 使用が簡単
  • 安定している
  • 実際のプロバイダに認証の必要がない
  • 実際のリソースをデプロイ・削除しない

静的解析ツールの弱み

  • 非常に限られた種類のエラーのみ発見できる
  • 機能性をチェックしないので、すべてのチェックが成功してもインフラが動かない可能性がある

プランテスト

terraform plan を実行し、プランの出力を解析する

静的解析より踏み込んでいるが、コードを完全に実行するわけではない

プランテストツール

  • Terratest
  • Open Policy Agent
  • Hashi Corp Sentinel
  • Checkov
  • terraform-compliance
  • terraform test で plan を使用する
    • v1.6で追加されたコマンド。本書はv1.3時点に書かれているそうなので、記載されていない

Terratestを用いた例

planの出力結果

Terraform will perform the following actions:

  # module.alb.aws_lb.example will be created
  + resource "aws_lb" "example" {
      + arn = (known after apply)
      + load_balancer_type = "application"
      + name = "test-4Ti6CP"
      (...)
  }

  (...)

Plan: 5 to add, 0 to change, 0 to destroy.

Terratestでのplanを使ったテスト

func TestAlbExamplePlan(t *testing.T) {
    t.Parallel()

    albName := fmt.Sprintf("test-%s", random.UniqueId())

    opts := &terraform.Options{
        // この相対パスは、自分の alb モジュールの example ディレクトリを
        // 指すよう変更すること
        TerraformDir: "../examples/alb",
        Vars: map[string]interface{}{
            "alb_name": albName,
        },
    }

    planString := terraform.InitAndPlan(t, opts)

    // plan の出力の add/change/destroy の数をチェックする方法の例
    resourceCounts := terraform.GetResourceCount(t, planString)
    require.Equal(t, 5, resourceCounts.Add)
    require.Equal(t, 0, resourceCounts.Change)
    require.Equal(t, 0, resourceCounts.Destroy)
}

Policy as Codeツール

  • Open Policy Agent(OPA)が人気
  • Rego という宣言型言語でポリシーをコートして記録できる
  • Terraformで管理しているリソースに ManagedBy というタグがあるかチェックする
// enforce_tagging.rego
package terraform

allow {
    resource_change := input.resource_changes[_]
    resource_change.change.after.tags["ManagedBy"]
}
  • 使い方
    • planの出力をプランファイルに保存する terraform plan -out tfplan.binary
    • OPAはJSONに対してのみ実行できる。JSONに変換 terraform show -json tfplan.binary > tfplan.json
    • JSONになったプランファイルをチェックする opa eval --data enforce_tagging.rego --input tfplan.json --format pretty data.terraform.allow

プランテストツールの強み

  • ユニットテスト・結合テストと静的解析の間の実行速度
  • 使いやすい
  • 安定している。不安定なテストはほとんどない
  • 実際のリソースを作成・削除しない

プランテストツールの弱み

  • 静的解析よりは多くのエラーを発見できる
  • プロバイダの認証が必要
  • 静的解析と同じく、テストが通ってもインフラが動かないことはあり得る

サーバテスト

サーバ(仮想サーバも含む)が正しく設定されているかテストすることに焦点を当てたテストツール

サーバテストツール

  • InSpec
  • Serverspec
  • Goss

InSpecの例

describe file('/etc/myapp.conf') do
  it { should exist }
  its('mode') { should cmp 0644 }
end

describe apache_conf do
  its('Listen') { should cmp 8080 }
end

describe port(8080) do
  it { should be_listening }
end

サーバテストツールの強み

  • ツールが提供するDSLで一般的な項目は簡単に確認できる
  • applyして、動作しているサーバを確認するので、より多くのエラーを発見できる。

サーバテストツールの弱み

  • 高速ではない。applyとdestroy(必要ないケースもあり)が必要になる
  • 実際にapplyするため、不安定なテストが存在する
  • プロバイダの認証が必要
  • リソースの作成・削除が必要。お金がかかる
  • サーバはチェックできるが、それ以外のインフラはチェックされない

ユニットテスト

Terraform におけるユニットは、再利用可能なモジュール

Terraform コードはAWSのAPIなどを呼びだすため、外部依存関係を全く無くす現実的な方法は存在しない

  • 純粋なユニットテストができない。実際のところ結合テストになる

実際のインフラを実際の環境にデプロイする自動テストを書くことで、Terraform コードが期待通りに動作するか確認できるため

基本戦略

  1. 小さく、独立したモジュールを作る
  2. terraform apply を実行し、実環境にデプロイする
  3. 期待通りに動作するか確認。ALBならHTTPリクエストを送る等
  4. terraform destroy で後片付け

terraform test で apply を使用する

  • v1.6で追加されたコマンド。本書はv1.3時点に書かれているそうなので、記載されていない

Terratest

  • terraform applyを実行し、動作確認をし、terraform destroy をする
  • HTTPリクエストの送信等のヘルパー関数が含まれる
  • terraform の出力変数の値を利用してテストコードを書ける
func TestAlbExample(t *testing.T) {
    opts := &terraform.Options{
        // この相対パスは、自分の alb モジュールの example ディレクトリを
        // 指すよう変更すること
        TerraformDir: "../examples/alb",
    }

    // テストの最後にすべてを後片付け
    defer terraform.Destroy(t, opts)

    // サンプルをデプロイ
    terraform.InitAndApply(t, opts)

    // ALB の URL を取得
    albDnsName := terraform.OutputRequired(t, opts, "alb_dns_name")
    url := fmt.Sprintf("http://%s", albDnsName)

    // ALB のデフォルトアクションが動作し、404 を返すことをテスト
    expectedStatus := 404
    expectedBody := "404: page not found"
    maxRetries := 10
    timeBetweenRetries := 10 * time.Second
    
    http_helper.HttpGetWithRetry(
        t,
        url,
        nil,
        expectedStatus,
        expectedBody,
        maxRetries,
        timeBetweenRetries,
    )
}

結合テスト

複数のUnitを組み合わせてテストをする

  • mysql serverの作成、mysql server を使用するweb app

E2E テスト

インフラが複雑になると実行に時間がかかりすぎる

現実的な対応として、本番に近いテスト環境を1回だけ構築し、動かしたままにする。

インフラコードに変更を加えたらテスト環境に変更を適用し、SeleniumなどでE2Eテストを実行する

その他:不安定なテストに対してリトライする

インフラのコードの定期的に自動テストをすると、不安定なテスト(flaky tests)に直面する

  • 時々EC2が立ち上がらないとか

Terratestを使っているなら、terraform.Options の MaxRetries、TimeBetweenRetries、RetryableTerraformErrors の各引数を使ってリトライを有効にする

2019/12/13

macOS Mojave + VirtualBox + Vagrantで作った環境で composer install が失敗する

環境
  • macOS Mojave: 10.14.6
  • VirtualBox: 6.0.12
  • php: 7.0.33
  • composer: 1.9.1
Vagrantでdebian環境を構築し、PHPのプロジェクトを共有フォルダでマウントする方式だった。
セットアップで vagrant ssh して、その中で composer install を実行したところ、1つ目のpackageのインストールが失敗して、以下のようなエラーが表示された。
- Installing ****/xxxxxxx (x.y.z): Reading /home/vagrant/.cache/composer/files/****/xxxxxxx/4beacec67ac5fe138813cdfd0ab1d031111111.zip from cache
Loading from cache
Extracting archiveExecuting command (CWD): unzip -qq  '/vagrant/hoge/vendor/****/xxxxxxx/98c734dfe8c02cf90edc8787111111111' -d '/vagrant/hoge/vendor/composer/zxcvbnm'
Plugin installation failed, rolling back
- Removing ****/xxxxxxx (x.y.z)

[RuntimeException]
Could not delete /vagrant/yoyaku/vendor/****/xxxxxxx/tests/HogeFuga:
結論としては、Vagrantfileの共有フォルダのtypeオプションに virtualboxが指定されていたので、削除すると動作した。
ファイルのパーミッションやcomposer周りを色々調べたが、時間の無駄だった。

2015/09/15

Dropboxで同期させてるDay Oneのエントリが増殖した

Day One/Journal.dayone/entries の下にエントリが1ファイルずつ存在しているが、
以下のように同じファイルが増殖してた。

4619D4A8395F4163B3CDA61BD40FB1F8 (1).doentry
4619D4A8395F4163B3CDA61BD40FB1F8 (2).doentry
4619D4A8395F4163B3CDA61BD40FB1F8 (3).doentry
4619D4A8395F4163B3CDA61BD40FB1F8.doentry

以下のコマンドで適当に削除して、再同期することで治った

cd ~/Dropbox/アプリ/Day\ One/Journal.dayone/entries
find . -type f -name '*(*' -print0 | xargs -0 rm -f

2015/08/03

php-fpmをServer::Starterを使ってHot deploy

したかったけど、ダメだった。

Server::Starterはサーバプログラムをよしなにホットデプロイしてくれるスーパーデーモンです。

FPM_SOCKETSを使ってsocketは引き継げるが、php-fpmがそもそもgraceful shutdownに対応してないため、Server::StarterがSIGHUPを受けてphp-fpmを切り替える際に処理途中のリクエストが切断される。

なんとかしたい……。

FPM_SOCKETSについて

php-fpmは環境変数のFPM_SOCKETSからsocket情報を引き継ぐ機能がある。

start_serverはsocket情報をSERVER_STARTER_PORTに入れてサーバプログラムに渡すので、FPM_SOCKETSにセットしてphp-fpmを起動するとよい。

ざっくり書くとこういう形

start.sh

#!/bin/bash
start_server --path=`pwd`/php-fpm.sock \
    --interval=15 \
    --signal-on-hup=QUIT -- \
    sh -c 'FPM_SOCKETS=$SERVER_STARTER_PORT php-fpm -y php-fpm.conf'

その他テスト用ファイル

php-fpm.conf

[global]
pid = /Users/yosasaki/devel/php/php-fpm-graceful/php-fpm.pid
error_log = /Users/yosasaki/devel/php/php-fpm-graceful/php-fpm-error_log
daemonize = no

[www]
listen = /Users/yosasaki/devel/php/php-fpm-graceful/php-fpm.sock
listen.backlog = 256
listen.allowed_clients = 127.0.0.1
listen.mode = 0660
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
slowlog = /Users/yosasaki/devel/php/php-fpm-graceful/www-slow_log
php_admin_value[error_log] = /Users/yosasaki/devel/php/php-fpm-graceful/www-error_log
php_admin_flag[log_errors] = on

index.php

<?php
sleep(10);
echo "OK";

nginx.conf

worker_processes  1;
daemon off;

events {
  worker_connections  1024;
}

http {
  include       mime.types;
  default_type  application/octet-stream;

  server {
    listen       8080;
    server_name  localhost;
    root /Users/yosasaki/devel/php/php-fpm-graceful;

    location / {
      fastcgi_pass   unix:/Users/yosasaki/devel/php/php-fpm-graceful/php-fpm.sock;
      fastcgi_index  index.php;
      include fastcgi.conf;
    }
  }
}

2015/07/22

CentOS 6.4でyum updateが"Error: Cannot retrieve metalink for repository: epel. Please verify its path and try again"で失敗する

epelの mirrors.fedoraproject.org とSSLコネクションをひらくところでコケている模様

解決方法

  1. /etc/yum.repos.d/epel.repoのmirrorlistがhttpsになっているので、一旦baseurlに変更する

    baseurl=http://download.fedoraproject.org/pub/epel/6/$basearch
    #mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-6&arch=$basearch
    
  2. ca-certificatesを更新

    % sudo yum update -y ca-certificates

2015/06/26

DockerでClojureを動かす

Docker containerでClojureのWAFであるLuminusを動かしてみる

事前準備

プロジェクト生成と実行

$ lein new luminus hello-world
$ cd hello-world/
$ lein run
Retrieving org/clojure/clojure/1.7.0-RC2/clojure-1.7.0-RC2.pom from central
Retrieving org/clojure/clojure/1.7.0-RC2/clojure-1.7.0-RC2.jar from central
2015-6-26 13:02:18 +0900 SPC-072.local INFO [hello-world.handler] -
-=[ hello-world started successfullyusing the development profile]=-
2015-06-26 13:02:18.357:INFO:oejs.Server:jetty-7.6.13.v20130916
2015-06-26 13:02:18.439:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:3000

ブラウザで開く

$ open http://localhost:3000

Dockerfile

方針

  • imageはdocker hubのjava8を使う
  • containerにuberjarを含める
    • leiningen runだとcontainer起動後から接続可能になるまで時間がかかる
    • Elastic Beanstalkだと結構致命的
  • CMDexec formじゃなくshell formで書く
    • sh経由で立ち上がるので、ENVでセットした環境変数が受け取れる
    • CMDならdocker run時に簡単に書き換えられる

Dockerfile

    FROM java:8

    ENV TZ JST-9
    ENV JVM_OPTS -server -Xms512m -Xmx512m -Xmn256m

    RUN mkdir -p /home/app
    COPY ./target/hello-worldjar /home/app/

    EXPOSE 3000

    WORKDIR /home/app
    CMD /usr/bin/java $JVM_OPTS -jar hello-world.jar 3000

詳しくはDockerfile referenceを参照。

containerの作成と立ち上げ

uberjar作成

$ lein uberjar
Compiling hello-world.core
Compiling hello-world.handler
Compiling hello-world.layout
Compiling hello-world.middleware
Compiling hello-world.routes.home
Compiling hello-world.session
Created /path/to/project/hello-world/target/hello-world-0.1.0-SNAPSHOT.jar
Created /path/to/project/hello-world/target/hello-world.jar

container作成

$ docker build -t luminus/hello-world .
Sending build context to Docker daemon 56.42 MB
Sending build context to Docker daemon
Step 0 : FROM java:8
 ---> 433801eb0894
Step 1 : ENV TZ JST-9
 ---> Running in ac5801626c85
 ---> 77b3c91b3d78
Removing intermediate container ac5801626c85
Step 2 : ENV JVM_OPTS -server -Xms512m -Xmx512m -Xmn256m
 ---> Running in 5c6a50907c9d
 ---> 9db9e3ecf034
Removing intermediate container 5c6a50907c9d
Step 3 : RUN mkdir -p /home/app
 ---> Running in 4e0e9d8c0b15
 ---> 9af2a4c10750
Removing intermediate container 4e0e9d8c0b15
Step 4 : COPY ./target/hello-world.jar /home/app/
 ---> 4e89615ff644
Removing intermediate container 88d653f5d04f
Step 5 : EXPOSE 3000
 ---> Running in 383fc9ad8ee1
 ---> 0ecb672ec459
Removing intermediate container 383fc9ad8ee1
Step 6 : WORKDIR /home/app
 ---> Running in eb575c33ce63
 ---> 158e8dbc87eb
Removing intermediate container eb575c33ce63
Step 7 : CMD /usr/bin/java $JVM_OPTS -jar hello-world.jar 3000
 ---> Running in 344eac7db8b2
 ---> 132b7b08093a
Removing intermediate container 344eac7db8b2
Successfully built 132b7b08093a

docker run

$ docker run --rm -it -p 3000:3000 luminus/hello-world
2015-Jun-26 13:47:52 +0900 9ae20b5deccf INFO [hello-world.handler] -
-=[ hello-world started successfully]=-
2015-06-26 13:47:52.424:INFO:oejs.Server:jetty-7.x.y-SNAPSHOT
2015-06-26 13:47:52.513:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:3000

-pオプションでcontainer側のTCP/3000をhost側(localhostじゃない)のTCP/3000にマッピングしているので、
boot2dockerコマンドでhost側のIPを調べて接続する

$ open http://$(boot2docker ip):3000

TODO

そのうち以下について書く

  • Docker Compose
  • Docker + ElasticBeanstalk

2015/03/04

Railsアプリをruby-profとqcachegrindでプロファイリング

遅いサイトをなんとかする必要があったので、まずは計測する。

最初に使ったrack-mini-profilerは大して役に立たないので無駄だった。

qcachegrindのインストール

% brew install qcachegrind graphviz

graphvizはqcachegrindでコールグラフの生成に使う

手順

  1. Gemfileにruby-profを追加

    group :profile do
      gem 'ruby-prof'
    end
    
  2. config.ruにprofの設定追加

    if Rails.env.profile?
      use Rack::RubyProf, :path => 'tmp/profile',
        :printers => {
          ::RubyProf::FlatPrinter => 'flat.txt',
          ::RubyProf::GraphPrinter => 'graph.txt',
          ::RubyProf::GraphHtmlPrinter => 'graph.html',
          ::RubyProf::CallStackPrinter => 'call_stack.html',
          ::RubyProf::CallTreePrinter => 'call_grind.txt',
        }
    end
    
  3. RAILS_ENV=profileの設定は適宜developmentあたりをコピーして作成。

  4. サーバを起動して、問題のページにアクセスする。

    ./bundle/bin/spring rails s -p 3001 -e profile
    
  5. tmp/profile/-call_grind.txtが生成されているのでqcachegrindに読み込ませる。

  6. Incl.やSelfの値の大きいところを目安にして、実際に遅い処理の部分を探す

2014/09/14

YAPC::Asia Tokyo 2014に行ってきました #yapcasia

YAPC::Asia Tokyo 2014

YAPC::Asia Tokyo 2014 公式サイト

大分報告が遅くなりました。

諸事情でトークは2,3つくらいしか見れなかったのですが、昨年以前と同様、各地のPerl Mongerと交流できたので満足です。無限コーヒーとワッフルが最高でした!周りに著名Perl Mongerがいるのでお話もできます。コーヒー最高!

PM繋がりで2日目の午後から、「地域.pmミートアップ 2014」というイベントでHokkaido.pmを代表してお話させていただきました。その様子はエンジニアtypeさんで記事になっています。

「『やろう』と言ったらそれはもう『.pm』」~YAPC::Asia Tokyo 2014に見る地方コミュニティの盛り上げ方

最近はSapporo.cljというClojureのイベントも主催しておりますが、Perlに限らず地域コミュニティはやりたい人が「やろう」と周りに宣言することから始まります。やりたい言語、技術があれば、どんどん自分から声をかけて行けばいいんじゃないでしょうか。

次のHokkaido.pm

非常によく「次のHokkaido.pmはいつですか?」と訊かれまして、お待たせてして申し訳ない気持ちでいっぱいでした。子育ても落ち着いてきましたので、10月末〜11月にHokkaido.pm#12を開催したいと思います。便乗帰省を目論んでいる方も暖かく迎え入れますので、是非ご参加ください。

2014/07/11

ClojureでFibonacci(10) Calculation per Request

Express vs Flask vs Go vs Sparkjava
https://medium.com/@tschundeee/express-vs-flask-vs-go-acc0879c2122

Clojureだとどの程度なのか気になったのでベンチとってみたら、
比較用のNodeの4倍程度速度だった。

GolangとSparkjavaはやはり速い……

環境

Hardware: Macbook Air 2011mid Core i7@1.8GHz and 4GB RAM
Software: OSX 10.9.3
Java 1.8.0_05 Java HotSpot(TM) 64-Bit Server VM

ソースコード

github.com/ysasaki/clj-fib-serverにアップしてある

src/fib/handler.clj


(ns fib.handler
  (:gen-class)
  (:require [compojure.core :refer :all]
            [compojure.route :as route]
            [ring.middleware.params :as mp]
            [org.httpkit.server :as httpkit]))

(defn- ^long fib [^long n]
  (case n
    0 0
    1 1
    (+ (fib (- n 1)) (fib (- n 2)))))

(defroutes app-routes
  (GET "/:number" {{number :number} :params}
       {:status 200 :header {"Content-Type" "text/plain"} :body (str (fib (Integer/parseInt number)))}))

(def app
  (mp/wrap-params app-routes))

(defn -main [port]
  (httpkit/run-server app {:port (Integer. port)}))

ベンチマーク

1回目

Running 30s test @ http://localhost:5000/10
  2 threads and 64 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     4.84ms   10.50ms 169.24ms   96.29%
    Req/Sec     9.76k     3.31k   14.07k    77.83%
  571981 requests in 30.00s, 51.82MB read
  Socket errors: connect 0, read 25, write 0, timeout 0
Requests/sec:  19065.88
Transfer/sec:      1.73MB

2回目。JVMが頑張っているのか2回目は大体1000req/secくらい速い

% wrk -c 64 -d 30s http://localhost:5000/10
Running 30s test @ http://localhost:5000/10
  2 threads and 64 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.42ms    5.11ms 133.44ms   99.18%
    Req/Sec    10.75k     1.43k   14.22k    85.30%
  605999 requests in 30.00s, 54.90MB read
  Socket errors: connect 0, read 3, write 0, timeout 0
Requests/sec:  20199.93
Transfer/sec:      1.83MB

fibにtype hintsを付けないと1000req/sec減る感じだった

Node

比較用にNodeも元記事のソースコードでベンチマーク

% node -v
v0.10.7

% wrk -c 64 -d 30s http://localhost:3000/10
Running 30s test @ http://localhost:3000/10
  2 threads and 64 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    12.72ms    1.51ms  30.10ms   71.00%
    Req/Sec     2.55k   224.26     3.03k    68.94%
  150699 requests in 30.00s, 31.19MB read
Requests/sec:   5022.71
Transfer/sec:      1.04MB

2014/06/24

Sapporo.clj#0 開催しました

参加者の皆様、@tnoborioさんありがとうございました。
誰にも参加意思を確認せずに開催に踏み切ってしまったので、最悪 @tnoborio
さんと二人きりかと思いましたが、予想外にあつまっていただいて感謝しております。

特に赤字覚悟で札幌まで来ていただいた登尾さん、本当にありがとうございました。
ニャンパスステッカーを寄付していただきましたので、#1以降で配っていきたいと思います。

次回以降ですが、隔月くらいの頻度でもくもく会なんかを開いていきたいところです。
参加者の皆さんにご協力いただくこともあるかと思いますので、よろしくお願いします。


最後に私のLTで使ったスライドのリンクを貼っておきます。

Web開発時におけるClojureとPerlのライブラリ比較です。
Clojureはさっとしか触っていないので、他にベターなもの等あるかと思います。
http://ysasaki.github.io/presentations/sapporoclj0/#/title

2014/06/20

Sapporo.cljを開催します

明日6/21(土)にSapporo.cljを開催します。

はじめてのClojureの著者 @tnobrio さんが来札されるので、 それに合わせての開催となります。

イベント詳細ページ

Sapporo.clj #0 「はじめてのClojure」出版記念
http://atnd.org/events/51603

私自身もClojureの勉強を始めたばかりで、わからないことだらけです。 参加者同士で互いにお役立ち情報をシェアしましょう。 需要があれば、今後もSapporo.cljを時々開いていきたいと思います。

はじめてのClojureについては著者割引があるそうなので、 事前に連絡をすると買えるんじゃないでしょうか。

2014/03/28

CentOS 6.x向けにremiのchef cookbook書いた

気づいたらopscodeのyumからremiが消えていて、何度も書くのが段々めんどうになったので作成

https://github.com/ysasaki/yum-remi

よんどころのない事情によりCentOS 6.x系でphp55が使いたい、そんな時に使ってください。

Berksfileに以下のようなものを追加

cookbook 'yum-remi', git: 'git://github.com/ysasaki/yum-remi.git'

後はrun listにrecipe[yum-remi]を追加して、remi-php55のリポジトリを有効にするだけです。

default['remi']['php55']['enabled'] = 1

remiのrpmをinstallして、/etc/yum.repos.d/remi.repoを上書きしているだけです。

2013/10/06

MTDDC Meetup HOKKAIDO 2013 に参加しました #mtddc

10月5日のMTDDC Meetup HOKKAIDOと翌日のHackathonに参加してきました。 非常に盛況で、予想よりも賑わってたのが印象的です。

ノベルティにMONA+SKという函館のお菓子が入ってて、これが結構美味しかったです。

さらにはじゃんけん大会でMovableType Tシャツをゲットできたので非常に満足度の高いイベントでした。

Hackathon

今回のHackathonではVagrantfileを含んだMTOSのアプリケーション環境丸ごとのchef cookbookを公開しました。
cookbook-movabletype-opensource-standalone

これは5ヶ月ほど前に作成したVagrantとchefのcookbookをブラッシュアップしたものです。
先にMTOSだけのcookbookは公開していましたが、Vagrantfileとその他のcookbookの設定等は含まれていませんでした。

今回は丸ごと配布なので、githubからcloneしてきてvagrant up --provisionを実行すると以下のような環境が作成されます。

  • CentOS 6.4
  • Perl 5.16.3
  • Nginx
  • MySQL

この環境はSkyarcさんのエンジニアブログの記事を元にしております。
デザイナー必見!VPSで高速なMovable Type用サーバをゼロから構築する方法

公開するに当たって、以前のバージョンに以下の作業を行ってます。

  • Vagrantfileをversion 2にアップデート
  • cookbookの管理をBerkshelfに移行

環境丸ごとのcookbookを公開しているのでVagrantでローカルに環境を作成するだけではなく、AWSのEC2上やWindows Azure、その他任意の場所のLinuxサーバにも簡単に環境を作れることになります。

2013/10/05

Vagrant + Chef Solo + Berksfileでのアプリケーション環境の作業手順

仕様変更だったり、ディレクトリ配置等が色々あるので自分の流儀を決める

Chef, Vagrantのインストール

chef関連ツールをインストール

> gem install chef knife-solo berkshelf

Vagrantはgemで入れると古いので公式サイトからパッケージでインストールする

Vagrant Pluginをインストール

> vagrant plugin install vagrant-berkshelf vagrant-vbox-snapshot

アプリケーションの雛形の作成

一番最初の雛形はknife soloで作成するのが無難

> knfie solo init foo

berksでBerksfile, Gemfile, Vagrantfileの雛形を生成する。gitの初期化もしてく
れる。既存ファイルを上書きするか聞かれるので"a"を押して、全部上書きする。

> berks init foo

cookbookの雛形を作成しておく

> knife cookbook create MyApp -o site-cookbooks

gitに突っ込んでおく

> git add -f * .chef/ .gitignore
> git commit

.chef/knife.rbにknife solo実行時のcookbook, role, node等のpathが入っているの
でこれは必須ファイル。このファイルがなくてハマることが多い

Vagrantの設定

いい感じに設定して、provisionをoffでとりあえず立ち上げる

> vagrant up --no-provision

chef soloの開発やsshで簡単に接続できるようにssh-configを書きだしておく。 この時ホスト名を分かりやすいものに置換しておくと良い

> vagrant ssh-config | sed 's/default/HOSTNAME/' >> ~/.ssh/config

置き換えたホスト名で接続確認

> ssh HOSTNAME

Chef SoloをVM側に容易

> knife solo prepare HOSTNAME

VMのスナップショットを作成

今後すぐに初期状態に戻せるようにスナップショットを作成しておく

> vagrant snapshot take chef-ready

Berksfileを更新

cookbook用のbundler。これから自分が書くcookbookの依存ファイルを追加する

> cat Berksfile
site :opscode

cookbook "yum"
cookbook "database"
cookbook "mysql"
cookbook "nginx"
cookbook "simple_iptables"
cookbook "openssl"

Cookbookを修正

好きなようにsite-cookbooks/MyApp/以下を修正していく

chef soloを実行

ある程度できたらVMにchefを適用する。

> knife solo cook HOSTNAME -V | tee install-log

-Vを付けて詳細なログを出す。長いのでinstall-logにも書きだしておく。 後はトライアンドエラーで徐々に修正していく

繰り返しすぎてよくわからなくなったりしたら、スナップショットの状態に戻して再度試す

> vagrant snapshot go chef-ready

完成

最終的にいい感じに仕上がったら、vagrantコマンドで一発で入るか確認する

> vagrant destroy
> vagrant up --provision

2013/09/22

YAPC::Asia 2013と今後のHokkaido.pmの活動について

YAPC::Asia 2013

今年もYAPC::Asiaに行ってきました。スタッフの皆さまのおかげで、非常に楽しい二日間を過ごせました。スタッフの皆さま、ありがとうございます!

普段お世話になっている方への挨拶や次回以降のHokkaido.pmでゲストとして招待したい人とコンタクトを取ることができたので、非常に満足しています。今回は前回よりも中々いい感じにいろんな人に会えた気がします。

今年は私事が色々と重なり、年内の予定が不明瞭だったためスピーカーには応募できませんでした。またスピーカーに応募したい思っていますが、次回のYAPC::Asiaの開催は不明ということで、とりあえずアウトプットを増やしつつ機会を待とうかなと思います。

今後のHokkaido.pm

次回のHokkaido.pmは1月後半から2月頃になるんではないでしょうか。もしかすると12月あたりにもあるかもしれません。

何人かに言われたので、そろそろUstをどうにかしたいところです。Ustがあれば遠方の方からも反応をもらえるのというメリットがありますし、土日に参加できない人が一定数いるようなので、そういった方にもフレンドリーかなと。また、先週札幌で行われたオープンソースカンファレンスでもHokkaido.pm Casualの空気感がわからず参加しにくいという話も聞きました。ブログ等での開催報告をもう少し頑張るというのももちろんですが、Ustも空気感を伝える手段の一つにもなるのかなと考えています。何か手頃なUSB接続のカメラを探したいと思います。

2013/09/03

Hokkaido.pm#10 を開催しました #hokkaidopm

8/31(土)に札幌市産業振興センターでHokkaido.pm#10を開催しました。
今回はJPA様の支援でゲストに@tokuhiromさんをおよびしてお話しして頂きましたありがとうございます。
さらにTengの中の人である@nekokakさんやPerl Beginners主催の@ytnobodyさん、mod_perl大好きな@xtetsujiにもお越しいただき大変豪華は顔ぶれとなりました。
皆様、まことにありがとうございます。

春から夏にかけて時間が取れなかったので前回の開催から半年程度間が開いてしまいました。
物足りない方は毎月第3水曜日開催のHokkaido.pm Casualに参加していただけると良いのではないでしょうか。
次回の開催日はまだ決まっていませんが半年に一度は開催したいと思っております。
ゲストの目星はある程度つけてありますので、9月のYAPC::Asiaで何人かにアプローチしたいと思います。

イベントのレポートはHokkaido.pm#10 開催報告を御覧ください。

LT - Asset Pipeline for Perl

今回はLTで『Asset Pipeline for Perl』という発表をしました。Railsについてるあの機能の一部をPlack::Middlewareとして実装したものです。
CoffeeScriptは私が使わないので対応していませんし、javascript_include_tagも未実装です。
もう少ししたら『GitHub止まりモジュール』から格上げされてCPANにアップロードするかもしれません。

2013/08/11

Movable Type Open SourceのChef recipeを更新

MTCafe Sapporo#3に参加したので、Movable Type Open Sourceのchef recipeを修正しました。
このrecipeはスカイアーク技術ブログに掲載されていた「デザイナー必見!VPSで高速なMovable Type用サーバをゼロから構築する方法」を自動化したものです。

https://github.com/ysasaki/cookbook-movabletype-opensource

主な変更点

  • git checkout時のreference(revision)をmasterからmt5.2.7に変更
  • perl-5.16.3のinstallをrootユーザに変更
  • htdocのmv時にonly_ifを追加し、ディレクトリがあるか確認を追加

git checkoutはとrevisionを指定しないとHEADになってしまうので、しっかり指定しないと後々面倒なことになる。

MTCafe Sapporo#3の感想

ハンズオンということでchef recipeを修正しつつ、簡単なMTMLを書いてた。
MTOSのソースコードは読んでたりするが、実は今までMTMLを書いたことがなかった。
Vimのpluginはなさそうなことを某S社の方が言っていたので、そこはちょっと残念。zen codingで書くしかないようだ。

タグについても色々と歴史的な事情があるのか自由な感じ。
mt:EntryTitleのようなタグのコロンを抜かせたり、case-insensitiveだったりする。
開始と終了タグが一致していればいいらしい。

テンプレートをコピペで管理画面上から貼り付けるのが面倒だったが、後で聞くとFTPでアップロードしたファイルに紐付けするような機能もあるらしい。

2013/07/18

daemontoolsのenvdirだけ欲しかったからEnvDir書いた

やっぱりenvdirしたかったので、作りかけだったのをちゃんと実装した。

俺得モジュールです。

使い方

    use strict;
    use warnings;

    # environment from /path/to/envdir/*
    use EnvDir -autoload => '/path/to/envdir', -clean;

-cleanを付けると本家のenvdir同様に%ENVをクリア(PATHのみは/bin:/usr/binになる)して、指定したdirのファイルから%ENVに色々セットします。
envdirをimportするか、OOスタイルで使うとガードオブジェクトが返ってきてスコープを抜けると元の%ENVに戻る

    use strict;
    use warnings;

    # import envdir function
    use EnvDir 'envdir', -clean;

    # Function style
    {
        my $guard = envdir('/path/to/envdir');
        ...
    }

    # OO style
    my $envdir = EnvDir->new( clean => 1 );
    {
        my $guard = $envdir->envdir('/path/to/envdir');
        ...
    }

envdir.plコマンドを添付しているので本家envdirと同じようにも使える

    > envdir.pl ./env sh -c 'echo $PATH'

2013/06/29

plenv installから--asが消えたのでperl-buildを直接使う

追記 2013/06/29 09:09

@tokuhiromさんにコメントでご指摘頂きましたところ、8日前にperl-build側で実装されたそうです。
githubにあるperl-buildのHEADを利用すると使えるようになります。


plenvの中身がperlからbashに変更された際に消えたようです。
バージョンはplenv 2.0.1-7-ge389af0

違うバージョンのperlを一つずつinstallする分には困りませんが、同じバージョンでコンパイルオプションを変更したものをinstallしようとすると「もうそのバージョンあるから!」とinstallを拒否されます。

ざっくりと見たところplenvは~/.plenv/versions以下にbuildしたperlを保存してます。

    > ls -1 ~/.plenv/versions/
    5.16.2
    5.16.3
    5.18.0

場所が分かれば後は、perl-buildで直接installしてやると大体うまく行きそうです。

    > perl-build 5.18.0 ~/.plenv/versions/5.18-ithreads -Duseithreads

無事installが終わるとこんな感じになるので、後はplenv global 5.18-ithreads等の通常の方法で切り替えることが出来ます。

    > plenv versions
      system
      5.16.2
      5.16.3
      5.18-ithreads
    * 5.18.0 (set by PLENV_VERSION environment variable)

公式に説明があるわけではないので自己責任で行ってください。

2013/06/17

Travis CIでbuild失敗時にエラーメッセージを確認する方法

ビルドに失敗した時に~/.cpanm/build.logを見たいことがあるので、以下の二つを最初から設定しておくと便利

  • install
  • after_failure

.travis.yml全体だとこんな感じ

    language: perl
    perl:
      - 5.10
      - 5.12
      - 5.14
      - 5.16
    install:
      - "cpanm --installdeps --notest . || cat ~/.cpanm/build.log"
    after_failure: 
      - "cat ~/.cpanm/build.log"

before_script, script等の各コマンドを上書きして全部に|| cat /path/to/logみたいなのを付けてる人もいた