CircleCIでRailsアプリをAmazon ECRにpushする

概要

railsアプリのテストとECRへのプッシュが目的。

サンプルコード

circle.yml
machine:
  services:
    - docker
  timezone:
    Asia/Tokyo
  environment:
    CIRCLE_ENV: test
dependencies:
  pre:
    - if [[ -e ~/docker/ruby.tar ]]; then docker load --input ~/docker/ruby.tar; fi
    - if [[ -e ~/docker/awesome-app-$CIRCLE_BRANCH.tar ]]; then docker load --input ~/docker/awesome-app-$CIRCLE_BRANCH.tar; fi
    - bundle --path=vendor/bundle
    - bundle exec rake assets:precompile
  cache_directories:
    - "~/docker"
    - "vendor/bundle"
    - "public/assets"
  override:
    - docker info
    - docker build -t $DOCKER_REPOS/awesome-app:$CIRCLE_BRANCH .
    - mkdir -p ~/docker
    - docker save -o ~/docker/ruby.tar ruby
    - docker save -o ~/docker/awesome-app-$CIRCLE_BRANCH.tar $DOCKER_REPOS/awesome-app:$CIRCLE_BRANCH
database:
  override:
    - bundle exec rake db:create db:schema:load db:migrate rake db:seed_fu
test:
  override:
    - bundle exec rubocop
    - bundle exec rspec
deployment:
  hub:
    branch: /^(master|staging)$/
    commands:
      - $(aws ecr get-login --region $AWS_REGION)
      - docker push $DOCKER_REPOS/awesome-app:$CIRCLE_BRANCH

dependencies

CircleCIだと、dockerイメージのキャッシュがされないので、
docker save & loadするっていうハックが一般的みたい。
~/dockerに逃してるが、将来docker imageがキャッシュされたら再検討。

bundleも忘れずにキャッシュされるようにしておく。

deployment

deploymentのセクションに関して、
master、stagingブランチの時だけECRにpushしたいという意図がある。
CIRCLE_BRANCHには、pushされたブランチ名が入るので、正規表現で切り分ける。

ENV

事前にCircleCI側にENVを設定する必要あり。
画面遷移: Setting->BUILD SETTINGS->Environment Variables

  • AWS_ACCESS_KEY_ID
  • AWS_ACCOUNT_ID
  • AWS_REGION
  • AWS_SECRET_ACCESS_KEY
  • DOCKER_REPOS
  • SECRET_KEY_BASE

続きを読む

AWS Lambda と Pythonを使ってメタデータをAmazon Elasticsearch Serviceにインデクシング

AWS Solutions Architect ブログ: 【AWS Database Blog】AWS Lambda と Pythonを使ってメタデータをAmazon Elasticsearch Serviceにインデクシング. 続きを読む

AWS Lambda(Python)によるサーバー簡易監視と、Slackでの結果通知

実現したかったこと

  • 運用中サーバーの簡易監視として、定期的にHTTPアクセスを行い、結果を確認したい。
  • サーバーレスで実行したい。
    • 対象サーバーにアクセスするIPを制限しているため、監視元は固定IPの必要がある。
  • 完全自動化し、監視結果だけが通知されて欲しい。

最終的に実現したこと

  • 全体イメージ
    全体イメージ

  • S3に監視先サーバーデータを配置する。

    • データの形式は以下の通り。

      servers.json
      {
          "servers": [
              {"name": "Google", "url": "http://www.google.co.jp"},
              {"name": "Yahoo", "url": "http://www.yahoo.co.jp"}
          ]
      }
      
  • AWS Lambda(Python)から上記のデータを読み込み、各サーバーにHTTPアクセスを行う。

  • 監視結果をSlackに通知する。

  • 上記を、CloudWatch Events - Scheduleで定期実行する。

設定詳細

VPC設定

IAM設定

  • Lambda作成時に、roleのtemplateとして、Simple Microservice permissionsを選択。
  • S3にアクセスするため、AmazonS3ReadOnlyAccessのポリシーをアタッチ。
  • LambdaVPC上で実行するため、AWSLambdaVPCAccessExecutionRoleのポリシーをアタッチ。

CloudWatch Events – Schedule設定

Slack

AWS Lambda(Python)

  • エラーハンドリング周りは改善の余地あり。
lambda_function.py
import json
import requests
import boto3

BUCKET_NAME = 'xxxxxxxxxx'
OBJECT_NAME = 'xxxxxxxxxx/servers.json'
SLACK_POST_URL = 'https://hooks.slack.com/services/xxxxxxxxxx/xxxxxxxxxx/xxxxxxxxxxxxxxxxxxxx'

def lambda_handler(event, context):
    json_data = __getServers()
    __check_server(json_data)

def __getServers():
   s3 = boto3.resource('s3')
   obj = s3.Object(BUCKET_NAME, OBJECT_NAME)
   response = obj.get()
   body = response['Body'].read()
   return body.decode('utf-8')

def __check_server(json_data):
    data = json.loads(json_data)
    servers = data['servers']

    has_error = False

    for server in servers:
        name = server['name']
        url = server['url']
        print("Check: " + name)

        try:
            r = requests.get(url)
            if r.status_code != 200:
                __send_error_message(name, url)
                has_error = True
        except requests.exceptions.RequestException as e:
            __send_request_error_message(name, url)
            has_error = True

    if has_error == False:
        __send_success_message()

def __send_error_message(name, url):
    payload = {
        "text": name + 'n' + url + 'n' + '*ERROR!*',
        "icon_emoji": ":x:"
    }
    __send_message(payload)

def __send_request_error_message(name, url):
    payload = {
        "text": name + 'n' + url + 'n' + '*Request Error!*',
        "icon_emoji": ":warning:"
    }
    __send_message(payload)

def __send_success_message():
    payload = {
        "text": "All Servers OK!",
        "icon_emoji": ":o:"
    }
    __send_message(payload)

def __send_message(payload):
    try:
        return requests.post(SLACK_POST_URL, json=payload)
    except requests.exceptions.RequestException as e:
        return None


AWS Lambda(Python)設定時の注意点

  • ライブラリはソースコードと同じディレクトリに配置する。
pip install requests -t .
  • ソースコードとライブラリをまとめて、zipにして配置する。
zip -r lambda_function.zip *

雑感

  • AWS LambdaにVPCを設定できるようになったことで、データ送信元を固定IPアドレスにしてLambdaを実行できるようになったため、使いどころが広がった。
  • 手軽な通知先として、Slackとの連携が簡単で便利すぎ。
  • servers.jsonの中身をbodyに詰めた、HTTP POST通信をトリガーに、API Gateway経由で実行させる方法も試したが、最終的に定期実行がラクな現在の形とした。

続きを読む

AWSPowershell.NetCore on PowerShell on macOS 環境構築

普段、職場やプライベートでAWSを利用する場合、Windowsマシンでaws-cliではなくAWSPowerShell(aws-cliのPowerShell版)を利用しています。 自宅のブレーカーが落ちてWindowsマシンが逝ってしまったため、やむを得ず サブ機のMacBookでも同じ環境でAWSを使えたらいいな、と思い、OSS/クロスプラットフォーム化したPowerShellおよびその上で稼働するAWSPowerShell.NetCoreをmacOSに入れてみました。以下、環境構築時の作業メモです。

前提環境

  • macOS Sierra
  • homebrewインストール済
  • homebrew-caskインストール済

環境構築手順

openssl & curl (by homebrew) インストール

macOSに同梱されているopensslはApple社独自開発のもので、一般的なLinuxディストリビューション等で利用されているopensslとは別物のようです。PowerShellは後者の方が相性がいいようなので、homebrewで後者に相当するものをインストールします。

wukann@mac ~$ brew install openssl
wukann@mac ~$ brew install curl --with-openssl

.NET Core requires Homebrew’s OpenSSL because the “OpenSSL” system libraries on macOS are not OpenSSL, as Apple deprecated OpenSSL in favor of their own libraries. This requirement is not a hard requirement for all of PowerShell; however, most networking functions (such as Invoke-WebRequest) do require OpenSSL to work properly.

蛇足:AppleとOpenSSL

AppleがOpenSSLを利用しなくなった経緯についてはこちら↓を参照。

PowerShellインストール

macOS向けのインストーラもあるようですが、今回はhomebrew-caskを利用します。

PowerShellインストール
wukann@mac ~$ brew cask install powershell
==> Caveats
A OpenSSL-backed libcurl is required for custom handling of certificates.
This is rarely needed, but you can install it with
  brew install curl --with-openssl
See https://github.com/PowerShell/PowerShell/issues/2211

==> Satisfying dependencies
==> Installing Formula dependencies from Homebrew
openssl ... already installed
complete
==> Downloading https://github.com/PowerShell/PowerShell/releases/download/v6.0.0-alpha.14/powershell-6.0.0-alpha.14.pkg
######################################################################## 100.0%
==> Verifying checksum for Cask powershell
==> Running installer for powershell; your password may be necessary.
==> Package installers may write to any location; options such as --appdir are ignored.
Password:
==> installer: Package name is powershell-6.0.0-alpha.14
==> installer: Installing at base path /
==> installer: The install was successful.
🍺  powershell was successfully installed!

一応、インストールされていることを確認。

PowerShellインストール確認
wukann@mac ~$ which powershell
/usr/local/bin/powershell

AWSPowershell.NetCoreインストール

PowerShellにもパッケージ(モジュール)管理機能「PowerShellGet」があります。今回インストールしたPowerShell v6には最初から入っているようです。これを利用してAWSPowerShell.NetCoreをインストールします。

PowerShellセッション起動

ここからはmacOSのshellセッションからPowerShellセッションを起動し、その上でPowerShellコマンド操作をします。

PowerShellセッション起動
wukann@mac ~$ powershell
PowerShell
Copyright (C) 2016 Microsoft Corporation. All rights reserved.

PS /Users/wukann>

PowerShellリポジトリ設定(PSGallery)

PowerShellGetでモジュールをインストールする場合、事前にモジュールを公開しているリポジトリを登録する必要があります。今回インストールするAWSPowerShell.NetCoreは、Microsoft公式のPowerShell Gallery(PSGallery)で公開されています。
登録済みリポジトリの情報はGet-PSRepositoryコマンドで取得できます。

登録済みPowerShellリポジトリ確認
PS /Users/wukann> Get-PSRepository

Name                      InstallationPolicy   SourceLocation
----                      ------------------   --------------
PSGallery                 Untrusted            https://www.powershellgallery.com/api/v2/

PowerShell Gallery(PSGallery)は最初から登録されていますが、InstallationPolicyUntrustedに設定されています。このままでもPSGalleryからモジュールをインストールできますが、インストールの度に「信頼できなリポジトリからモジュールをインストールしますか?」という確認メッセージにY/N対応する必要があります。
今回はPSGalleryを「信頼済みのリポジトリ」として設定します。

PSGalleryを信頼済みリポジトリに設定
PS /Users/wukann> Set-PSRepository -Name PSGallery -InstallationPolicy Trusted

設定が反映されていることを確認。

PSGallery設定確認
PS /Users/wukann> Get-PSRepository

Name                      InstallationPolicy   SourceLocation
----                      ------------------   --------------
PSGallery                 Trusted              https://www.powershellgallery.com/api/v2/

AWSPowershell.NetCoreインストール

リポジトリの設定が済んだところで、Install-ModuleコマンドでAWSPowerShell.NetCoreをインストールします。

AWSPowerShell.NetCoreインストール
PS /Users/wukann> Install-Module -Name AWSPowerShell.NetCore -Scope CurrentUser

念のため、Get-InstalledModuleコマンドでインストール済みモジュールを確認。

インストール済みモジュールの確認
PS /Users/wukann> Get-InstalledModule

Version    Name                                Repository           Description
-------    ----                                ----------           -----------
1.1.2.0    PackageManagement                   https://powershel... PackageManagement (a.k.a. OneGet) is a new way to discover and in...
1.1.2.0    PowerShellGet                       https://powershel... PowerShell module with commands for discovering, installing, upda...
3.3.38.0   AWSPowerShell.NetCore               PSGallery            The AWS Tools for PowerShell Core lets developers and administrat...


補足・-Scopeオプションなし or -Scope AllUsersを指定した場合

今回、Install-Moduleコマンドに-Scope CurrentUserオプションを付けてモジュールをインストールしました。このオプションがない場合、-Scope AllUsersがデフォルトで指定されます。んで、そうするとこの↓ようにエラーとなります。

-ScopeをCurrentUserにしないで実行した場合
PS /Users/wukann> Install-Module -Name AWSPowerShell.NetCore -Scope AllUsers
PackageManagementInstall-Package : Administrator rights are required to install modules in '/usr/local/microsoft/powershell/6.0.0-alpha
.14/Modules'. Log on to the computer with an account that has Administrator rights, and then try again, or install '/Users/wukann/.local
/share/powershell/Modules' by adding "-Scope CurrentUser" to your command. You can also try running the Windows PowerShell session with
elevated rights (Run as Administrator).
At /usr/local/microsoft/powershell/6.0.0-alpha.14/Modules/PowerShellGet/1.1.2.0/PSModule.psm1:1809 char:21
+ ...          $null = PackageManagementInstall-Package @PSBoundParameters
+                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (Microsoft.Power....InstallPackage:InstallPackage) [Install-Package], Exception

エラーメッセージを見る限りではPowerShellをsudoで起動すれば解決する気がしますが、「ここまでsudo無しで進めてこられたのにここだけsudoするのもなぁ…」ということで試していません。

AWSPowershell.NetCoreインポート

Notice:ここで取り上げているモジュールのインポート(Import-Module)は、そのセッション内でのみ有効です。powershellセッションを立ち上げ直した場合、再度インポートし直す必要があります。
(この件に関する対処方法もいつか書ければ…)

ここまでの手順でAWSPowershell.NetCoreをインストールできましたが、この状態ではコマンドを利用できません。PowerShellセッションにモジュールが読み込まれていないためです。セッションに読み込まれ、利用可能なモジュールを確認するには、Get-Moduleコマンドを実行します。

利用可能モジュール確認
PS /Users/wukann> Get-Module

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Manifest   3.1.0.0    Microsoft.PowerShell.Management     {Add-Content, Clear-Content, Clear-Item, Clear-ItemProperty...}
Manifest   3.1.0.0    Microsoft.PowerShell.Utility        {Add-Member, Add-Type, Clear-Variable, Compare-Object...}
Script     1.1.2.0    PackageManagement                   {Find-Package, Find-PackageProvider, Get-Package, Get-PackageProvider...}
Script     1.1.2.0    PowerShellGet                       {Find-Command, Find-DscResource, Find-Module, Find-RoleCapability...}
Script     1.2        PSReadLine                          {Get-PSReadlineKeyHandler, Get-PSReadlineOption, Remove-PSReadlineKeyHandle...

AWSPowershell.NetCoreが一覧になく、セッションに読み込まれていないことが確認できます。
モジュールをセッションに読み込むには、Import-Moduleを実行します。

AWSPowerShell.NetCoreをPowerShellセッションに読み込む
PS /Users/wukann> Import-Module AWSPowerShell.NetCore

再度Get-Moduleコマンドを実行すると、AWSPowerShell.NetCoreがセッションに読み込まれたことが確認できます。

Get-Module
PS /Users/wukann> Get-Module

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Binary     3.3.38.0   AWSPowerShell.NetCore               {Add-AASScalableTarget, Add-ACMCertificateTag, Add-ADSConfigurationItemsToA...
Manifest   3.1.0.0    Microsoft.PowerShell.Management     {Add-Content, Clear-Content, Clear-Item, Clear-ItemProperty...}
Manifest   3.1.0.0    Microsoft.PowerShell.Utility        {Add-Member, Add-Type, Clear-Variable, Compare-Object...}
Script     1.1.2.0    PackageManagement                   {Find-Package, Find-PackageProvider, Get-Package, Get-PackageProvider...}
Script     1.1.2.0    PowerShellGet                       {Find-Command, Find-DscResource, Find-Module, Find-RoleCapability...}
Script     1.2        PSReadLine                          {Get-PSReadlineKeyHandler, Get-PSReadlineOption, Remove-PSReadlineKeyHandle...

実際にAWSPowerShell.NetCoreのコマンド(Get-AWSPowerShellVersion)を実行してみます。

AWSPowerShell.NetCoreのコマンド実行
PS /Users/wukann> Get-AWSPowerShellVersion

AWS Tools for PowerShell Core
Version 3.3.38.0
Copyright 2012-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.

Amazon Web Services SDK for .NET
Core Runtime Version 3.3.7.1
Copyright 2009-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.

Release notes: https://aws.amazon.com/releasenotes/PowerShell

This software includes third party software subject to the following copyrights:
- Logging from log4net, Apache License
[http://logging.apache.org/log4net/license.html]

ヨッシャ(*´ω`*)

続きを読む