Glide Note

glidenote's blog

AWS Application Load Balancer + Amazon ECS でDockerのホットデプロイ環境を構築した

TL;DR

  • AWS Application Load Balancer(以下ALB) + Amazon ECS でDockerのホットデプロイ環境を構築した
  • ALBのTarget GroupとECSのServiceを紐付けることで、ALB配下のコンテナの入れ替えが自動で行われるようになる

ALBは先日リリースされたばかりで、私もまだ色々と検証している段階なので、内容や認識等に誤りがあるかもしれないのでご容赦下さい。(詳しい人教えてください!!)

その他弊社の前提情報

  • GitHub + CircleCIが連携済み
  • Docker RepoにはAmazon EC2 Container Registry(以下ECR)を利用
  • DeployはGitHubのデプロイブランチへのマージを契機にCircleCI経由で、Docker Pushとecs-deployでDockerデプロイを実施

準備

ALBとECSの設定については@inokaraさんのブログが詳しいので、そちらを参照ください。 今回はALBのDynamic Port Mappingは利用してません。

デプロイフロー

デプロイフローは下記のような形になってます。

デプロイ前の稼働中の状態

  • ALBは80,443ポートで稼働
  • コンテナではnode.jsのアプリが3000ポートで稼働

デプロイ直後の状態

  • CircleCI経由で、ecs-deployを実行し、新しいコンテナを作成。
  • 新しいコンテナが起動すると、自動でALB配下に追加されアクセスを流れる
  • 古いコンテナと新しいコンテナが混在する

ecs-deployは下記のような形で実行。CircleCI上ではAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY を環境変数に設定し、引数に利用しているregionを-r us-west-1を追加して実行してます。

1
2
3
4
5
ecs-deploy \
-c クラスター名 \
-n サービス名 \
-i xxxxxxxxxxxx.dkr.ecr.us-west-1.amazonaws.com/kaizenplatform/kaizen-xxxxxxxx:947 \
-t 300

デプロイ部分のdocker pushecs-deploy合わせて1分半くらいで完了している。

デプロイ完了後の状態

  • しばらくすると古いコンテナが破棄され、新しいコンテナだけで稼働する
  • 一連の作業中にリクエストを流し続けて、サービスが停止しないことも確認

ecs-deployの実行が走ってから、新しいコンテナが起動し、古いコンテナが廃棄されるまで、 大体6分くらい要している。

ALBとECSの初期設定が結構面倒ですが、設定さえ終われば、 新旧コンテナの入れ替え、ALB配下への追加削除が自動で行われるようになるので大変便利。

引き続きDynamic Port Mappingを利用した構成も検証中。

参考

Alpine LinuxなDockerイメージにServerspecを実行する環境を作った

TL;DR

  • Alpine LinuxなDockerイメージにServerspecを実行する環境をMacとCircleCI上に作った
  • CircleCI環境では lxc-attach コマンドが必要なので、spec_helper.rb で環境差を吸収するようにした
  • 今後よく利用しそうなので、流用しやすい形でGithubに置いておいた

前提

最近Kaizen Platform, Inc.で利用している一部Docker ImageをAmazon LinuxベースのものからAlpine Linuxベースのものに置き換え中。 Alpine Linuxについては@stormcat24さんのブログが一番参考になります。

今までDockerイメージにServerspecを実行するときには、コンテナ内でsshdを立てて、ssh経由でknife-soloでプロビジョニングを実行し、その後同じくssh経由でServerspecを流していた。

Alpine Linuxベースに切り替えてから、出来るだけイメージサイズを小さくするためにknife-soloは利用せずに、Dockerfile だけで構築している。(Dockerfileだけが良いかは現在検証中) knife-soloのためにコンテナ内でsshdを立てる必要はなくなったので、同じくssh経由で実行していたServerspecdocker-api 経由で実行するようにした。

実行環境

  • Mac OS X
    • ProductVersion: 10.11.6
    • Ruby 2.3.0
    • Docker 1.12.0
  • CircleCI
    • Ruby 2.3.0
    • Docker 1.9.1-circleci-cp-workaround
  • serverspec 2.36.0
  • docker-api 1.31.0

実際の作業

ファイル構成

先に作業後のファイル構成を書いておくと下記のような感じになります。

1
2
3
4
5
6
7
8
9
10
.
├── Dockerfile
├── Gemfile
├── Gemfile.lock
├── Rakefile
├── circle.yml
└── spec
    ├── docker
    │   └── package_spec.rb
    └── spec_helper.rb

Gemfile

Gemfileを用意して bundle install

1
2
3
4
5
source 'https://rubygems.org'

gem 'rake'
gem 'serverspec'
gem 'docker-api'

Dockerfile

Dockerfileを用意。debugしやすいようにbashだけ導入

1
2
3
FROM alpine:3.4

RUN apk add --no-cache bash

tagは docker-alpine-serverspec-sample としてbuild。

1
docker build -t docker-alpine-serverspec-sample .

Serverspec各種ファイル

serverspec-init で各種ファイルを作成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
⇒  serverspec-init
Select OS type:

  1) UN*X
  2) Windows

Select number: 1

Select a backend type:

  1) SSH
  2) Exec (local)

Select number: 2

 + spec/
 + spec/localhost/
 + spec/localhost/sample_spec.rb
 + spec/spec_helper.rb
 + Rakefile
 + .rspec

生成されるsampleのテストは利用しないので削除

1
rm -rf spec/localhost

ローカル用の spec_helper.rb

1
2
3
4
5
6
7
8
9
require 'serverspec'
require 'docker'

set :backend, :docker
set :docker_url, ENV["DOCKER_HOST"]
image = Docker::Image.build_from_dir('.')
set :docker_image, image.id

Excon.defaults[:ssl_verify_peer] = false

テストファイルの追加

ディレクトリの作成し、Dockerfileのパッケージインストールに対応するテスト spec/docker/package_spec.rb を追加

1
mkdir -p spec/docker/
1
2
3
4
5
require 'spec_helper'

describe package('bash') do
  it { should be_installed }
end

Serverspecの実行

テストの準備が整ったので、Serverspecを流してみる。

1
bundle exec rake spec

問題がなければ下記のようになる。

1
2
3
4
5
Package "bash"
  should be installed

Finished in 1.61 seconds (files took 0.67509 seconds to load)
1 example, 0 failures

CircleCI上での実行

ローカルに続いて、CircleCI環境でも動くようにする。

circle.yml の用意

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
machine:
  timezone: UTC
  ruby:
    version: 2.3.0
  services:
    - docker

dependencies:
  pre:
    - bundle install

test:
  pre:
    - docker version
    - docker info
    - docker build -t ${CIRCLE_PROJECT_REPONAME} . :
        timeout: 1200
    - docker run ${CIRCLE_PROJECT_REPONAME} &
    - sleep 5
  override:
    - bundle exec rspec
    - docker ps -a
    - docker images

CircleCI でも動くようにspec_helper.rbの修正

公式ドキュメント に記載されているようにCircleCIのDockerでは docker exec が利用できず、 lxc-attach コマンドを利用しないといけないので、spec_helper.rb でMacとの環境差を吸収し、同じコマンドでServerspecが流せるようにする。

元同僚の@ngs自身のブログに書いていたのでそれを利用。

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
require 'serverspec'
require 'docker'

set :backend, :docker
set :docker_url, ENV["DOCKER_HOST"]
image = Docker::Image.build_from_dir('.')
set :docker_image, image.id

Excon.defaults[:ssl_verify_peer] = false

# https://circleci.com/docs/docker#docker-exec
if ENV['CIRCLECI']
  module Docker
    class Container
      def exec(command, opts = {}, &block)
        command[2] = command[2].inspect # ['/bin/sh', '-c', 'YOUR COMMAND']
        cmd = %Q{sudo lxc-attach -n #{self.id} -- #{command.join(' ')}}
        stdin, stdout, stderr, wait_thread = Open3.popen3 cmd
        [stdout.read, [stderr.read], wait_thread.value.exitstatus]
      end
      def remove(options={})
        # do not delete container
      end
      alias_method :delete, :remove
      alias_method :kill, :remove
    end
  end
end

これで、Mac上でもCircleCI上でも同じ

1
bundle exec rake spec

でテストが実行できるようになった。

↑の画像のように、イメージのサイズが非常に小さいAlpine Linuxに切り替えてからbuildもtestもすぐに完了するので生産性が高くなった。

参考

Mackerelのページを瞬時に開くAlfred Workflowを作った

Mackerelを利用していて、

  • 特定のホストのメトリクス
  • 特定のサービスのメトリクス
  • 特定のダッシュボード

などを見るときにページにアクセスして探すのに若干手間がかかるので、Alfredから瞬時に開けるようにWorkflowを作った。

導入方法や使い方はREADMEを参照ください。 動作は下記のような感じになります。(サービスとダッシュボードを開く動作はキャプチャに秘匿情報が含まれているので割愛してます bow )

関連

最近導入した開発に役立つ便利なステータスバー通知系アプリ3選

最近追加したステータスバーの通知系アプリで便利なやつを共有。

GitHub Notifications

GitHubのNotifications通知については、Gitifyを利用。 それまでは自分宛の通知はZapier使ってSlackに通知したり、Chrome Extensionとか使って検知してたんですが、 ステータスバーに通知するやつが自分にはあっていたので、半年くらい前から利用してます。

CircleCI Notifications

CircleCIの通知にはSeaEyeを利用。特定プロジェクトや、自分のビルドだけ通知などが設定ができるのが大変便利。

BitBar & Sensu Notifications

rebuild.fm a132で話題に出ていたBitBarで、KAIZENで利用している監視システムSensuのPluginがあったので導入。 Sensuがアラートを検知した場合、Pagerduty経由で、Slack、メール、電話、スマホアプリへの通知などをしてくれるので、無くても良いんですが、ちょっとBitBarを利用してみたかったので導入。

これを機にメールとSlackでの通知も減らしたので作業に集中する時間が増えた(気がする)

参考

CircleCIのProjectページの移動が簡単になるAlfred Workflowを作った

実はCircleCI Advent Calendar 2015 - Qiitaにエントリするために、 結構前にAlfred Workflowを作っていたんですが、当時多忙でブログに書くのを忘れていました sweat

CircleCIで利用するProject数が増えると、それぞれのページに移動するのが めちゃくちゃ面倒なので、CircleCIのProject移動が簡単になるAlfred Workflowを作りました。

インストール方法、使い方はREADMEを見ていただくことにして、 どんな感じで動作するのかgif animationにしてみました。

Projectページを開く

URL情報をcacheしているので、サクサク動作します。

各Projectのmasterブランチのstatusを確認する

その都度APIを叩いて確認しているので、レスポンスが遅めです。

CircleCIとAlfredを利用している方は是非ご活用ください。