ようへいの日々精進XP

よかろうもん

YAPC::Fukuoka 2017 に途中まで参加した

YAPC::Fukuoka

「やぷし」という名前はずーっと聞いていたけど、なかなか参加出来ずにいたら福岡で開催するってことで募集が開始されたら速攻で申し込んだ。

yapcjapan.org

申し込んだ時のパスワード忘れて参加票の 2 次元バーコードを取り出せずにアタフタしたけど、無事に会場に潜入することが出来た。

初めて LINE Fukuoka

会場は博多駅から徒歩一分の LINE Fukuoka さんのシャレオツオフィス。

linefukuoka.co.jp

シャレオツ過ぎて写真を撮るのすら忘れた。

ボクと Perl の関わり

Hello world レベル。

途中までの参加だったけど

奥さんの体調が悪かったり、掃除当番をさぼったツケがあったりして途中までの参加になったけど、お土産も沢山頂いたし、刺激となるようなお話も聴けたので十分にモトは取れた。

参加したセッションとざっくりとした感想

参加したセッション

Perl は公私共に使ったことがない身分ですが

最初の 2 セッションはそれぞれアプローチの方法等は異なるものの、古い Perl バージョンとどのように付き合ってきたか、付き合っていくかのお話だっと思う。

  • 既に安定して動いてしまっているアプリケーション遺産に手を加えるのは大変そう…これって、言語に関係なく言えることなんだろうなあ
  • ユニットテスト等もメンテナンスされなくなる
  • 出来るだけ小さくシンプルにリリースを保つことで Perl のバージョンアップの手間を最小限に抑える努力をされているとのこと(これって、Perl に限らず他の言語でも言えることなんだろうなあ)
  • ペパボのインフラエンジニアの皆さんには Golang が根付いていて、テストも書いちゃうらしい…スゴイなあ

クラウドエンジニアの三大美徳

Azure Web apps を例にクラウドエンジニアの三大美徳(怠惰であれ、短気であれ、傲慢であれ)を説かれた。

  • 運用するな開発せよ…確かに、そう思う
  • OS の管理をしたくない…その通り、やりたくない
  • ネットワーク構成まで Infrastructure as a code したい…うむ、ぜひやりたい

コンテナ = Docker にあらず

ペパボの @udzura さん、haconiwa の udzura さん。

@udzura さんや @ten_forwardLinux コンテナ関連の資料は本当に勉強になるし、これらの資料を読むたびに Docker に踊らされていた自分が恥ずかしくなる。(決して Docker が悪いわけでは無い)

とにかく、コンテナ = Docker にあらず、cgroup や Linux Namespace や Linux Capability 等の技術の結集であるという点は忘れないようにしたい。

発表の内容とは関係ないけど、@udzura さんの発表のテンポがとても気に入っている。

ペパボさん x Github Enterprise x OpenStack

細かい技術のお話は出てこなかったが、ペパボさんが Github Enterprise(以後、GHE) を利用して、エンジニアだけではなく非エンジニアの方も巻き込んで生産性の向上にどのように取り組んでいるか等のお話。

アプリケーションリリース時のタグ打ちを自動化したり、エンジニアの評価を Pull Request ベースで行っていたり、それだけでなく企画進行等非エンジニアの方も積極的に利用されているのに驚かされた。また、それらのやり取りが GHE を通して全てのメンバーが見ることが出来る風通しの良さ。ほんと面白いというか凄い。メールを書いたりするような感覚で当たり前に GHE を使っちゃっているんだろうなあ。

生まれ変わったら試用期間でもいいから一度はペパボで仕事したいと思った。

ということで

途中までの参加となった YAPC::Fukuoka だけど、暑い博多で熱い気持ちになることが出来たと思うし、全てのセッションを通じて感じたのはコードが書けるようになりたいなあと思った次第(なんでか分からないけど)

登壇された皆さん、本当にありがとうございました。会場を提供して下さった LINE Fukuoka さんも有難うございました。そして…ムーン人形の頭をベタベタ触ってしまい本当に申し訳ございませんでした(初めての LINE Fukuoka で興奮していたのと、自分の頭に似ていたのでつい…)

2017 年 06 月 30 日(金)

今日は

5 回目の結婚式記念日。

ジョギング

  • 香椎浜 x 2 周
  • 右かかとの痛みがあるのでペースはゆるりと

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

夕飯

JAYA で料理長特製のピザとパスタ。どちらもクオリティ高い。

JAYA から帰ってきたら、奥さんがアイスを爆食いしてて、気付いたら気持ち悪いと言って横になっていた。 こういうところも奥さんらしくて好きなところである。

2017 年 06 月 28 日(水)

ジョギング

  • 引き続き、お休み
  • 右足かかとの痛み

日課

  • (腕立て x 30 + 腹筋 x 30 ) x 3

自宅インターネット

がお昼前に復旧した。

サポートセンターのオペレータの対応に少しイラッときた瞬間があったけど、とにかく直ってよかった。

夕飯

カレーを作る。

自分はトロみが少ない方(よりスープ的な感じ)が好みだったので、好みの感じで作れたと思っていたが、奥さんには若干不評だった。

仕事用デスク

夕方からはベランダがとても涼しいので、ベランダで作業が出来るようにポータブルデスクを購入した。

自宅インターネットも復旧したので、仕事用の机をダイレックス香椎店で新調したでござる。これからの季節、夕方から夜にかけてのベランダ作業が捗りそうでござります。

2017 年 06 月 27 日(火)

ジョギング

  • お休み
  • 右足かかとの痛み

日課

  • も無し

自宅インターネット

が使えなくなる。

仕方ないので博多でコワーキング借りようと思ってブラブラしていたら、結局、いつもの筑紫口二階のプロント。但し、今日はビール無し。

ずーっとテザリングでデータ使用量心配だし、zoom とかで打ち合わせ出来ないので辛い。

夕飯

奥さんと待ち合わせて「ひかり」で食べる。

穴子の天ぷらはとても美味しかったけど、他のお刺身等は割高感があった。普通にゴマサバとか頼んでおけば良かったと後悔。

2017 年 06 月 26 日(月)

ジョギング

  • 右足のかかと付近が痛いので散歩

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

夕飯

奥さんがササッと作ったゴーヤと豚肉の炒め物が美味しかった。ちなみに、ゴーヤは実家の庭で採れたやつ。

2017 年 06 月 25 日(日)

ジョギング

  • 右足のかかと付近に痛みがあって香椎浜 x 1 周
  • 太腿をかばったりしながら走っていたしわ寄せがきたのかな…

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

奥さんと博多デート

  • 奥さんがレッスンに行っている間は、筑紫口 2 階のプロントで待機
  • その後、博多阪急でお中元の品選び
  • 阪急の 8F で全国うまいもの市的な催事があったので試食しまくる為に立ち寄る
  • 結局、試食はそこそこに東北地方の日本酒が呑める立ち飲みバーで味付け玉子を肴に利き酒セットを頂く
  • ヨドバシで iPad mini 4 を見ただけ、奥さんのドライヤーを手配して香椎に戻る

夕飯

  • よし本で 1000 円セットとイカセット

Apache の mod_security を使って POST リクエストの内容をログに残す試み

モチベーション

Apache + PHP で運用している、とあるサービスのとあるエンドポイントについて、POST される際のデータに異常があり、レスポンスに異常が発生しているという体で、どんなデータが POST されているのかをログに残して分析したい。

やりたいこと

  • POST リクエストの内容をログに残したい
  • あくまでも POST リクエストのみを取得し、出来れば、任意のリクエストパスのみをログに残したい

この記事で書けないこと

  • mod_security の詳細
  • mod_security の導入後、Web サービスのパフォーマンスにどのような影響が出たか等

検討

実装各種

以下の実装について導入を検討、検証した。

mod_dumpio

  • Apache License 2.0
  • Apache が受け取ったすべての入力と Apache により送られたすべての出力との、両方もしくはどちらか一方を、 エラーログファイルにログ収集できる
  • 全ての入出力は要らない、必要な入力だけを制御する方法を見つけられずに候補から外す

mod_mruby

  • MIT License
  • Wiki にとても良いサンプルがあった
  • 絶対、mod_mruby 採用だと思った
  • ところが、mod_php と組み合わせて利用すると body のデータが mod_php まで渡せないので PHP で実装されている検証アプリケーションが動かなくなった(涙
  • 引き続き調べたい

mod_security

  • Apache License 2.0
  • Apache のモジュールとして動作する WAF(Web Application Firewall)
  • リクエストフィルタリング、パラメータフィルタリング、監査ログ、HTTPS フィルタリング等の機能がある

mod_mruby をめちゃくちゃ利用したかったんだけど、上述の通り、検証アプリケーションが動かなくなってしまったので、次の候補として考えていた mod_security を利用して POST リクエストをログに残してみたい。

mod_security による POST リクエストのロギング

mod_security について

上述の通り、リクエストやパラメータのフィルタリング、POST 等の通常では取得出来ないログの収集を行うことが出来る。

試した環境

以下の通り、Debian Jessie 上に Apache 2.4.10 と PHP 7.0.20 を導入した環境で試す。

$ cat /etc/debian_version
8.8

$ apache2 -v
Server version: Apache/2.4.10 (Debian)
Server built:   Feb 24 2017 18:40:28

$ /usr/local/bin/php --version
PHP 7.0.20 (cli) (built: Jun 13 2017 22:23:54) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies

検証アプリケーション

FuelPHP で実装した、メモを登録、閲覧、編集等を REST API で操作するアプリケーションを利用する。

#
# メモの登録
#
curl -X POST "http://127.0.0.1/memo/write" -d "memo=aaaaaaaaa"

#
# 全てのメモの一覧を JSON で取得
#
curl -X GET "http://127.0.0.1/memo/all"

#
# メモの内容を修正
#
curl -X POST "http://127.0.0.1/memo/edit/1" -d "memo=areertertertertretertretre"

メモ登録の際に送信する POST データ(memo=xxxxxxxx)の内容がログに記録されるまでがとりあえずのゴール、

mod_security のインストー

apt-get update
apt-get install -y libapache2-modsecurity

以上。

インストールが完了すると以下のように設定ファイル作成される。

$ pwd
/etc/apache2
$ ls -l mods-enabled | grep security
lrwxrwxrwx 1 root root 32 Jun 25 04:19 security2.conf -> ../mods-available/security2.conf
lrwxrwxrwx 1 root root 32 Jun 25 04:19 security2.load -> ../mods-available/security2.load

security2.conf の中身は以下のようになっており、フィルタリング等に必要な設定は /etc/modsecurity/ 以下に拡張子 .conf というファイル名で置けば良さそうだ。

$ cat security2.conf
<IfModule security2_module>
        # Default Debian dir for modsecurity's persistent data
        SecDataDir /var/cache/modsecurity

        # Include all the *.conf files in /etc/modsecurity.
        # Keeping your local configuration in that directory
        # will allow for an easy upgrade of THIS file and
        # make your life easier
        IncludeOptional /etc/modsecurity/*.conf
</IfModule>

POST データをロギングする為の mod_security の設定

ドキュメント等を見ながら以下のような設定を作成した。

$ pwd
/etc/modsecurity

$ cat mod_security_rule.conf
SecRuleEngine On
SecRequestBodyAccess On

SecAuditLog /var/log/apache2/post-request.log
SecAuditLogParts ABCFHZ
SecRule REQUEST_METHOD "POST" "id:100000,phase:2,nolog,pass"
SecRule REQUEST_URI "^\/memo/write$" "id:100001,ctl:auditEngine=On"

各ディレクティブについては以下の通り。

ディレクティブ 概要
SecRuleEngine On 後述のルールエンジンを有効にする
SecRequestBodyAccess ON POST のフィルタリングを有効にする(これを有効にしないと POST リクエストの中身は覗けない)
SecAuditLog /var/log/apache2/post-request.log 監査ログのパスを指定(このファイルに POST リクエストの中身が記録される)
SecRule REQUEST_METHOD “@beginsWith POST” “id:100000,phase:2,nolog,pass” REQUEST_METHOD という変数の値が POST で始まる場合にアクション "id:100000,phase:2,nolog,pass" を実行する
SecRule REQUEST_URI “^\/memo/write$” “id:100001,ctl:auditEngine=On” 同様に REQUEST_URI という変数に ^\/memo/write$ が含まれている場合にアクション id:100001,ctl:auditEngine=On を実行する

その他のディレクティブ等については、以下の重厚なリファレンスを確認すること。

github.com

尚、SecRule は以下のような書式となる。

SecRule VARIABLES OPERATOR [ACTIONS] 

例えば…

SecRule REQUEST_METHOD "@beginsWith POST" "id:100000,phase:2,nolog,pass"

だと、以下のような意味となる。

  • 検索対象は REQUEST_METHOD
  • "@beginsWith POST"REQUEST_METHOD の値が POST で始まる場合のリクエストを対象
  • ユニークな ID 100000 を付与
  • プロセスフェーズ phase2 を付与(2 は request フェーズで 4 が response となり 5 が logging となる)

(引き続き、調べて書く)

動かしてみる

  • メモを登録する
$ curl -X POST "http://127.0.0.1/memo/write" -d "memo=hogehoge" -i
HTTP/1.1 200 OK
Date: Sun, 25 Jun 2017 07:06:23 GMT
Server: Apache/2.4.10 (Debian)
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT
Access-Control-Max-Age: 1000
Access-Control-Allow-Headers: x-requested-with, Content-Type, origin, authorization, accept, client-security-token
X-Powered-By: PHP/7.0.20
Content-Length: 0
Content-Type: text/html; charset=UTF-8
  • メモが登録されていることを確認する
$ curl -s GET "http://127.0.0.1/memo/all" | jq '.[]|select(.memo|contains("hogehoge"))'
{
  "id": "26",
  "memo": "hogehoge",
  "created_at": "2017-06-25 16:06:23",
  "updated_at": "2017-06-25 16:06:23"
}
  • POST したデータがログに記録されていることを確認する
--95a03a77-A--
[25/Jun/2017:07:06:23 +0000] WU9g76wRAAMAAAAWsgQAAAAH 172.17.0.1 43092 172.17.0.3 80
--95a03a77-B--
POST /memo/write HTTP/1.1
Host: 127.0.0.1
User-Agent: curl/7.43.0
Accept: */*
Content-Length: 13
Content-Type: application/x-www-form-urlencoded

--95a03a77-C--
memo=hogehoge
--95a03a77-F--
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT
Access-Control-Max-Age: 1000
Access-Control-Allow-Headers: x-requested-with, Content-Type, origin, authorization, accept, client-security-token
X-Powered-By: PHP/7.0.20
Content-Length: 0
Content-Type: text/html; charset=UTF-8

--95a03a77-H--
Message: Warning. Pattern match "^\\/memo/write$" at REQUEST_URI. [file "/etc/modsecurity/mod_security_rule.conf"] [line "9"] [id "100001"]
Apache-Handler: application/x-httpd-php
Stopwatch: 1498374383196210 456570 (- - -)
Stopwatch2: 1498374383196210 456570; combined=89, p1=0, p2=84, p3=0, p4=0, p5=4, sr=0, sw=1, l=0, gc=0
Producer: ModSecurity for Apache/2.8.0 (http://www.modsecurity.org/).
Server: Apache/2.4.10 (Debian)
Engine-Mode: "ENABLED"

--95a03a77-Z--

上記の通り、--95a03a77-C-- パート以下に POST データが記録されている。

  • POST するんだけど、ログ取得対象では無いエンドポイントについてはログは記録されないことを確認する
$ curl -X POST "http://127.0.0.1/memo/edit/26" -d "memo=fugafuga" -i
HTTP/1.1 200 OK
Date: Sun, 25 Jun 2017 07:11:49 GMT
Server: Apache/2.4.10 (Debian)
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT
Access-Control-Max-Age: 1000
Access-Control-Allow-Headers: x-requested-with, Content-Type, origin, authorization, accept, client-security-token
X-Powered-By: PHP/7.0.20
Content-Length: 0
Content-Type: text/html; charset=UTF-8

メモが更新されていることを確認。

$ curl -s GET "http://127.0.0.1/memo/all" | jq '.[]|select(.memo|contains("fugafuga"))'
{
  "id": "26",
  "memo": "fugafuga",
  "created_at": "2017-06-25 16:06:23",
  "updated_at": "2017-06-25 16:11:50"
}

ログは記録されていないことを確認。

$ sudo grep "fugafuga" /var/log/apache2/post-request.log
$

以上

mod_mruby でとても良いサンプルがあったのに、mod_mruby が利用出来なかったのは残念だったけど、mod_security を使うことで通常のアクセスログやエラーログだけで解析することが難しい Web アプリケーションの不具合等を調査する為の情報収集が簡単に行えるのは素晴らしい。(mod_security の本来の使い方では無いかもしれないが)

今後、実際のアプリケーション環境に mod_security を導入し、パフォーマンスへの影響等について引き続き検証を行いたい。

2017 年 06 月 24 日(土)

ジョギング

日課

  • (腕立て x 30 + 腹筋 x 30) x 3

一区切り

色々と苦しいこともあったけど、とりあえず一区切りついたのでホッとしている。これからは自分たちの生活を大切にしていきたい。

夕飯

自宅で鉄板焼き。お肉は少なめ、野菜多め。

CircleCI と CodeDeploy のチュートリアル(出来るだけ awscli でやるよ)

ググれば

いくらでも情報は出てくるので、それらの情報を参考にしてチュートリアルしてみる。

circleci.com

docs.aws.amazon.com

dev.classmethod.jp

構成

下図のような構成を想定している。

f:id:inokara:20170625000540p:plain

チュートリアルでは以下のような作業を行う。

  • CircleCI 用の IAM ユーザー作成
  • デプロイ用 S3 バケット作成
  • CodeDeploy の設定
  • CircleCI の設定

チュートリアル

CircleCI 用 IAM User 作成

  • デプロイ用 S3 への put 権限と CodeDeploy 用の権限を付与
$ cat oreno-application_user_policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "codedeploy:RegisterApplicationRevision",
        "codedeploy:GetApplicationRevision"
      ],
      "Resource": [
        "arn:aws:codedeploy:*:*:application:oreno-application"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "codedeploy:CreateDeployment",
        "codedeploy:GetDeployment"
      ],
      "Resource": [
        "arn:aws:codedeploy:*:*:deploymentgroup:oreno-application/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "codedeploy:GetDeploymentConfig"
      ],
      "Resource": [
        "arn:aws:codedeploy:*:*:deploymentconfig:CodeDeployDefault.OneAtATime",
        "arn:aws:codedeploy:*:*:deploymentconfig:CodeDeployDefault.HalfAtATime",
        "arn:aws:codedeploy:*:*:deploymentconfig:CodeDeployDefault.AllAtOnce"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject"
      ],
      "Resource": [
        "arn:aws:s3:::oreno-application/*"
      ]
    }
  ]
}

以下を実行してポリシーを作成する。

export _AWS_PROFILE=oreno-profile
export _AWS_REGION=ap-northeast-1
export _POLICY_ARN=$(aws --profile ${_AWS_PROFILE} --region ${_AWS_REGION} \
  iam create-policy \
    --policy-name oreno-application_user_policy \
    --policy-document file://oreno-application_user_policy.json \
    --query Policy.Arn \
    --output text)
echo ${_POLICY_ARN}
  • ユーザーの作成とポリシーのアタッチ
#
# ユーザーの作成
#
aws --profile ${_AWS_PROFILE} --region ${_AWS_REGION} \
  iam create-user \
    --user-name oreno-application

#
# 作成したユーザーにポリシーをアタッチ
#
aws --profile ${_AWS_PROFILE} --region ${_AWS_REGION} \
  iam attach-user-policy \
    --user-name oreno-application \
    --policy-arn ${_POLICY_ARN}
  • アクセスキーとシークレットアクセスキーを作成
aws --profile ${_AWS_PROFILE} --region ${_AWS_REGION} \
  iam create-access-key \
    --user-name oreno-application

以下のように出力されるので AccessKeyIdSecretAccessKey を控えておく。

{
    "AccessKey": {
        "UserName": "oreno-application",
        "Status": "Active",
        "CreateDate": "2017-06-24T02:34:21.549Z",
        "SecretAccessKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "AccessKeyId": "AKXXXXXXXXXXXXXXXXXX"
    }
}

デプロイ用 S3 バケット作成

  • S3 バケットを作成する
aws --profile ${_AWS_PROFILE} --region ${_AWS_REGION} \
  s3 mb s3://oreno-application
  • 作成したバケットを確認する
aws --profile ${_AWS_PROFILE} --region ${_AWS_REGION} \
  s3 ls | grep 'oreno-application'

以下のように出力されることを確認する。

2017-06-24 11:37:37 oreno-application

CodeDeploy 設定

  • パラメータと設置値
パラメータ 備考
Service Role Name oreno-application-role 変数: _SERVICE_ROLE_NAME
Service Role Policy Name oreno-application-role-policy 変数: _SERVICE_ROLE_POLICY_NAME
Application Name oreno-application 変数: _APPLICATION_NAME
Deployment Group Name oreno-application-group 変数: _DEPLOYMENT_GROUP_NAME
Deployment Config Name CodeDeployDefault.OneAtATime 変数: _DEPLOYMENT_CONIG_NAME
EC2 tag Key deploy EC2 タグに指定しておく
EC2 tag Value true EC2 タグに指定しておく

ちなみに、Deployment Config には以下のような種類がある。

パラメータ ざっくり説明
CodeDeployDefault.OneAtATime Deploy 対象 1 台ずつに対して Deploy を行う
CodeDeployDefault.AllAtOnce 全ての Deploy 対象に対して一度に Deploy を行う
CodeDeployDefault.HalfAtATime Deploy 対象の半分にまず Deploy を行う
  • CodeDeploy に付与する Service Role を作成する
$ cat oreno-application-role.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "codedeploy.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

以下を実行して Service Role を作成する。

export _SERVICE_ROLE_NAME=oreno-application-role
export _SERVICE_ROLE_ARN=$(aws --profile ${_AWS_PROFILE} --region ${_AWS_REGION} \
  iam \
    create-role \
      --role-name ${_SERVICE_ROLE_NAME} \
      --assume-role-policy-document file://oreno-application-role.json \
      --query Role.Arn \
      --output text)
echo ${_SERVICE_ROLE_ARN}
  • Service Role にポリシーを付与する
$ cat oreno-application-role-policy.json
{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Resource": "*",
            "Action": [
                "ec2:Describe*"
            ]
        }
    ]
}

以下を実行して Service Role に Policy を追加する。

export _SERVICE_ROLE_POLICY_NAME=oreno-application-role-policy
aws iam put-role-policy \
  --role-name ${_SERVICE_ROLE_NAME} \
  --policy-name ${_SERVICE_ROLE_POLICY_NAME} \
  --policy-document file://oreno-application-role-policy.json
  • アプリケーションの作成
export _APPLICATION_NAME=oreno-application
aws --profile ${_AWS_PROFILE} --region ${_AWS_REGION} \
  deploy create-application \
    --application-name ${_APPLICATION_NAME}

以下のように出力される。

{
    "applicationId": "12345678-1234-5678-9012-1abcde01a123"
}
  • Deployment Group の作成
export _DEPLOYMENT_GROUP_NAME=oreno-application-group
export _DEPLOYMENT_CONIG_NAME=CodeDeployDefault.OneAtATime
aws --profile ${_AWS_PROFILE} --region ${_AWS_REGION} \
  deploy create-deployment-group \
    --application-name ${_APPLICATION_NAME} \
    --deployment-group-name ${_DEPLOYMENT_GROUP_NAME} \
    --deployment-config-name ${_DEPLOYMENT_CONIG_NAME} \
    --ec2-tag-filters Key=deploy,Value=true,Type=KEY_AND_VALUE \
    --service-role-arn ${_SERVICE_ROLE_ARN}

ここまでで CodeDeploy を利用する準備が出来たはず。

CodeDeploy Agent の導入

今回は CentOS 7 に導入する。

$ cat /etc/system-release
CentOS Linux release 7.3.1611 (Core)
  • 導入
sudo yum -y update
sudo yum -y install ruby wget
wget https://aws-codedeploy-ap-northeast-1.s3.amazonaws.com/latest/install
chmod +x ./install
sudo ./install auto
  • 確認
$ sudo service codedeploy-agent status
The AWS CodeDeploy agent is running as PID 2223

$ systemctl list-unit-files | grep codedeploy
codedeploy-agent.service                      enabled

よし。

サンプルアプリケーションの用意

こちらのサンプルアプリケーションを利用する。

mkdir circleci-tutorial
cd circleci-tutorial
aws s3 cp s3://aws-codedeploy-ap-northeast-1/samples/latest/SampleApp_Linux.zip . --region ap-northeast-1
unzip SampleApp_Linux.zip
rm SampleApp_Linux.zip

事前に GitHub に追加していた circleci-tutorial というリポジトリにサンプルアプリケーションを追加する。

$ tree .
.
├── LICENSE.txt
├── README.md
├── appspec.yml
├── index.html
└── scripts
    ├── install_dependencies
    ├── start_server
    └── stop_server

1 directory, 8 files

appspec.yml は以下の通り。

$ cat appspec.yml
version: 0.0
os: linux
files:
  - source: /index.html
    destination: /var/www/html/
hooks:
  BeforeInstall:
    - location: scripts/install_dependencies
      timeout: 300
      runas: root
    - location: scripts/start_server
      timeout: 300
      runas: root
  ApplicationStop:
    - location: scripts/stop_server
      timeout: 300
      runas: root

CircleCI の設定

ずっと CLI でやりかったけど、ここからは GUI で。

  • プロジェクトの追加

f:id:inokara:20170624225129p:plain

サンプルアプリケーションを追加していた circleci-tutorial をプロジェクトとして追加する。

  • AWS アクセスキーとシークレットアクセスキーを追加

f:id:inokara:20170624225144p:plain

f:id:inokara:20170624225201p:plain

f:id:inokara:20170624225628p:plain

控えておいたアクセスキーとシークレットアクセスキーを追加する。

  • circle.yml を作成
cd circleci-tutorial
cat << EOT >> circle.yml
test:
  override:
    - echo 'test ok.'
deployment:
  staging:
    branch: master
    codedeploy:
      ${_APPLICATION_NAME}:
        application_root: /
        region: ap-northeast-1
        revision_location:
          revision_type: S3
          s3_location:
            bucket: ${_APPLICATION_NAME}
            key_pattern: ${_APPLICATION_NAME}-{BRANCH}-{SHORT_COMMIT}
        deployment_group: ${_DEPLOYMENT_GROUP_NAME}
        deployment_config: ${_DEPLOYMENT_CONIG_NAME}
EOT

circle.yml は以下のようになる。

$ cat circle.yml
test:
  override:
    - echo 'test ok.'
deployment:
  staging:
    branch: master
    codedeploy:
      oreno-application:
        application_root: /
        region: ap-northeast-1
        revision_location:
          revision_type: S3
          s3_location:
            bucket: oreno-application
            key_pattern: oreno-application-{BRANCH}-{SHORT_COMMIT}
        deployment_group: oreno-application-group
        deployment_config: CodeDeployDefault.OneAtATime

サンプルアプリケーションをデプロイ

サンプルアプリケーションの index.html を以下のように修正する。

$ git diff index.html
diff --git a/index.html b/index.html
index 4feaaa6..ba32312 100644
--- a/index.html
+++ b/index.html
@@ -26,8 +26,7 @@
 </head>
 <body>
   <div align="center">
-    <h1>Congratulations</h1>
+    <h1>俺のアプリケーション</h1>
     <h2>This application was deployed using AWS CodeDeploy.</h2>
     <p>For next steps, read the <a href="http://aws.amazon.com/documentation/codedeploy">AWS CodeDeploy Documentation</a>.</p>
   </div>

git push をする。

$ git add index.html
$ git commit -m "update"
[master 88c6bea] update
 1 file changed, 1 insertion(+), 2 deletions(-)
$ git push
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 320 bytes | 0 bytes/s, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To git@github.com:inokappa/circleci-tutorial.git
   29cd755..88c6bea  master -> master

CircleCI でデプロイ済み。

f:id:inokara:20170624225728p:plain

以下の通り、俺のアプリケーションがデプロイされた。

f:id:inokara:20170624225715p:plain

ということで

CircleCI 用の IAM ユーザーに付与するポリシーで少しハマったけど、思ったよりも簡単に CircleCI と CodeDeploy を組み合わせることが出来た..気がする。