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]

ヨッシャ(*´ω`*)

続きを読む

OpsWorks管理下のAmazon LinuxをCLIでアップグレードする

はじめに

何かにつけ、GUIが苦手です。WEBブラウザを開くと、トンデモなバナーをクリックしてしまうし、そもそもトンデモなバナーが出来てきてしまうネットワーク広告が怖い。
OpsWorks(AWSマネジメントコンソール)では、広告は表示されないのですが、いつか広告モデルになるかもしれない…
そんな不安から日々のオペレーションは、awscliを用いたCLIで完結したいというのがモチベーションです。
今回は、OpsWorksで唯一GUIなオペレーション(awscliにサブコマンドが用意されていない)となるUpgrade Operating SystemをCLIで実施するコネタを紹介します。

バージョン

動作を確認している環境とそのバージョンは、以下の通りです。

  • OpsWorks(リモート環境)

    • Cehf 11.10
    • Berkshelf 3.2.0
    • Amazon Linux 2016.03 → 2016.09
  • Mac(ローカル環境)
    • aws-cli 1.11.28 Python/2.7.10 Darwin/15.6.0 botocore/1.4.85

Custom JSONの準備

下ごしらえとして、OpsWorksに渡すattributeをCustom JSONとしてJSONフォーマットのファイルにまとめておきます。
OpsWorksのビルドインcookbookであるdependenciesのattributeを上書きします。詳細は、後述します。

$ mkdir ./aws/opsworks && vi $_/upgrade-amazonlinux.json

{
  "dependencies": {
    "os_release_version": "2016.09",
    "allow_reboot": false,
    "upgrade_debs": true
  }
}

コマンド

CLIでAmazon Linuxをアップグレードしていきます。

幸せなchefになるために、独自の味付けをしない、つまり可能な限りビルドインのcookbookを利用するべきです。
Upgrade Operating Systemで実施しているのは、update_dependenciesというdeployになり、dependencies::updateレシピを実行しています。該当のレシピを一読すると、yum -y updateコマンドを実行していました。前述のCustom JSONは、yum -y updateするために必要なattributeとなります。

  • os_release_versionは、アップグレードしたいAmazon Linuxのバージョンを指定します。
  • allow_reboot は、パッケージのアップデートの後に再起動するか指定します。今回は、インスタンスの停止を明示的に実施しますので、falseとしておきます。
  • upgrade_debsは、一見Debianぽいですがパッケージをアップデートするか否かのフラグとして実装されてます。今回は、アップデートするのでtrueとしておきます。

Upgrade Operating Systemの正体を把握できたので、awscliで以下のような一連コマンドを実行していきます。

# 1. Stackのリビジョンを指定
$ aws opsworks --region us-east-1 update-stack --stack-id STACK_ID --custom-cookbooks-source "{"Revision":"UgradeAmazonLinux"}"

# 2. Stackで管理している全EC2インスタンスに対して、update_custom_cookbooksの実行(最新版cookbookを配置)
$ aws opsworks --region us-east-1 create-deployment --stack-id STACK_ID --command "{"Name":"update_custom_cookbooks"}"

# 3. opsworks agentのバージョンアップ(最新版を利用する)
$ aws opsworks --region us-east-1 update-stack --stack-id STACK_ID --agent-version LATEST

# 4. Custom JSONとレシピを指定して、全パッケージをアップデート
$ aws opsworks --region us-east-1 create-deployment --stack-id STACK_ID --instance-ids INSTANCE_ID01 INSTANCE_ID02 --command "{"Name":"execute_recipes","Args":{"recipes":["dependencies::update"]}}" --custom-json file://./aws/opsworks/upgrade-amazonlinux.json

# 5. EC2インスタンスの停止
$ aws opsworks --region us-east-1 stop-instance --instance-id INSTANCE_ID01
$ aws opsworks --region us-east-1 stop-instance --instance-id INSTANCE_ID02

# 6. OpsWorksで保持しているOSのバージョン情報を更新
$ aws opsworks --region us-east-1 update-instance --instance-id INSTANCE_ID01 --os "Amazon Linux 2016.09"

# 7. EC2インスタンスの起動
$ aws opsworks --region us-east-1 start-instance --instance-id INSTANCE_ID01
$ aws opsworks --region us-east-1 start-instance --instance-id INSTANCE_ID02

4でビルドインのcookbookにCustom JSONでattributeを渡し、全パッケージのアップデートを実施します。
5でEC2インスタンスを停止するのは、以下の2つの理由があります。

  • OpsWorksが保持しているEC2インスタンスの情報を更新するためには、該当のEC2インスタンスを停止する必要がある
  • OSアップグレード後は、setupライフサイクルイベントを実施することを推奨されている

setup ライフサイクルイベントは、7の起動時に実行されます。

おわりに

AWSが広告モデルになったら嫌ですね。
Enjoy CLI!

参考

続きを読む

起動中のEC2インスタンスの名前一覧を取得するワンライナー

よく忘れる:frowning2:のでメモ。手元のmacで実行してます。

$ aws ec2 describe-instances --profile dev --filter Name=instance-state-code,Values=16 | jq -r ".Reservations[].Instances[].Tags | map(select(.Key == "Name")) | .[].Value | sort"
db1
db2
web1
web2
:

instance-state-codeやtagの取得名を変えれば、停止中のインスタンス一覧特定のタグ名一覧を取得することもできます。ユニークな値が欲しい場合は、uniqコマンドにパイプするだけです。

留意点として

  • --profileの値は適宜読み替えてください
  • 指定するprofileには、予めEC2の読み取り権限を付けておいてください
  • awsclijqコマンドを使うので、無かったらインスールしてください。
    (sortも使いますが、たいていのディストリビューションであればインストールされていると思われます)

各コマンドのバージョンは以下になります。

$ aws --version
aws-cli/1.11.34 Python/2.7.13 Darwin/15.6.0 botocore/1.4.91
$ jq --version
jq-1.5

参考

AWS CLI のインストールと設定
http://docs.aws.amazon.com/ja_jp/streams/latest/dev/kinesis-tutorial-cli-installation.html

続きを読む

Amazon EC2 VPCのIPv6対応 インスタンスからのIPv6アドレス通信

やったこととサマリ

構築した環境と疎通を試したIPv6通信

オハイオリージョンの同一サブネット内に ubuntu 16.04 LTS のインスタンスを2つ立てて、下記のIPv6通信をしてみた。

  1. 同一サブネット内のインスタンス間の直接IPv6通信

    • グローバルユニキャストアドレス経由
    • リンクローカルユニキャストアドレス経由
  2. All Node Address (ff02::1) リンクローカルマルチキャストアドレスあての通信
  3. stateful DHCPv6に頼らず勝手IPv6アドレスをインスタンスに付与しての通信

サマリ

  • インスタンス間の直接IPv6通信はグローバルアドレス, リンクローカルアドレスともに制限なくできた。
  • All Node Address (ff02::1) へのping6 (ICMP echo request送信) で近隣ノード(デフォルトルータを含む)を見つけられない。
  • 勝手にIPv6アドレスを割り当てても使えずAWSのインフラが割り当てたIPv6アドレスだけしか使えない。現時点(2017.1.15)ではVPN用途でユーザが自前のグローバルIPv6アドレスを持ち込んだり、プライベートIPv4アドレスの感覚で、ユニークローカルIPv6アドレス(ULA)を付けられない様子。

構成図

VPCの同一サブネット内にインスタンスを2つ立てた。

                                             +---------+
                                             |    GW   |
                                             +----+----+
                                                  |RA fe80::4fd:d1ff:fec8:f9cf
                                                  |↓
   2001:1f16:XXXX:YYYY::/64([P1]と表記)            |
   --+------------------------------------+-------+--------
     |                               |
     |     [P1]:f557:112e:f9bd:c7f3  |     [P1]:d326:143a:2015:79fa
     |eth0 fe80::4df:a5ff:fe6c:5d57  |eth0 fe80::4f0:13ff:feeb:c61d
+----+----+                     +----+----+
| ubuntu1 |                     | ubuntu2 |
+---------+                     +---------+

インスタンス間の直接IPv6通信

ubuntu1 to ubuntu2 (グローバルユニキャストアドレス)

OK

ubuntu1# ping6 2600:1f16:XXXX:YYYY:d326:143a:2015:79fa
PING 2600:1f16:8df:XXXX:YYYY:112e:f9bd:c7f3(2600:1f16:XXXX:YYYY:f557:112e:f9bd:c7f3) 56 data bytes
64 bytes from 2600:1f16:XXXX:YYYY:f557:112e:f9bd:c7f3: icmp_seq=1 ttl=64 time=0.523 ms
64 bytes from 2600:1f16:XXXX:YYYY:f557:112e:f9bd:c7f3: icmp_seq=2 ttl=64 time=0.603 ms
^C

ubuntu1 to ubutu2 (リンクローカルユニキャストアドレス)

OK

ubuntu1# ping6 fe80::4f0:13ff:feeb:c61d%eth0
PING fe80::4f0:13ff:feeb:c61d%eth0(fe80::4f0:13ff:feeb:c61d) 56 data bytes
64 bytes from fe80::4f0:13ff:feeb:c61d: icmp_seq=1 ttl=64 time=0.466 ms
64 bytes from fe80::4f0:13ff:feeb:c61d: icmp_seq=2 ttl=64 time=0.553 ms
^C

ubuntu1 to All Nodes Address (リンクローカルマルチキャスト)

ubuntu1# ping6 ff02::1%eth0
64 bytes from fe80::4df:a5ff:fe6c:5d57: icmp_seq=1 ttl=64 time=0.024 ms
64 bytes from fe80::4df:a5ff:fe6c:5d57: icmp_seq=2 ttl=64 time=0.032 ms

同一リンク内にいるはずの、ubuntu2からもデフォルトルータからECHO replyは来ず、自分自身からのみ返事がくる。ubuntu2側のeth0を見ていてもECHO requestが来ないので、インスタンス間にある仮想スイッチで止められている動きだった。

ubunut1の近隣キャッシュを見ると

ubuntu1# ip -6 nei
fe80::4f0:13ff:feeb:c61d dev eth0 lladdr 06:f0:13:eb:c6:1d STALE
fe80::4fd:d1ff:fec8:f9cf dev eth0 lladdr 06:fd:d1:c8:f9:cf router STALE

ICMP ECHO requst/reply は疎通しないもののの、ubuntu2,デフォルトルータいずれも近隣探索は成功しておりMACアドレスの解決はできている。仮想スイッチは近隣探索は通している。

RAで通知されたデフォルトルータへのアクセス

ubuntu1# ip -6 route
fe80::/64 dev eth0  proto kernel  metric 256  pref medium
default via fe80::4fd:d1ff:fec8:f9cf dev eth0  proto ra  metric 1024  expires 1799sec hoplimit 64 pref medium

ubuntu1# ping6 fe80::4fd:d1ff:fec8:f9cf%eth0
^C

リンクローカルユニキャストアドレスでデフォルトルータへICMP ECHO requstを飛ばしても返事なし。

インスタンスに勝手IPv6アドレスをつける

prefix::1 (グローバルユニキャストアドレス)をつける

stateful DHCPv6で割り当てられるIPv6アドレス(マネージメントコンソールで確認できるIPv6アドレス)ではないアドレスを手動でつけて通信を試みる。

ubuntu1 to Internet (インスタンス to Internet)

ubuntu1# ip -6 addr add 2001:1f16:XXXX:YYYY::1/64 dev eth0

DADの重複検知がないことを確認して

# ping6 ipv6.google.com
PING ipv6.google.com(2607:f8b0:4001:c09::71) 56 data bytes
^C

結果: IPv6インターネットへの通信不可

ubuntu1 to ubuntu2 (インスタンス同士)

ubuntu1# ping6 2600:1f16:XXXX:YYYY:d326:143a:2015:79fa
PING 2600:1f16:XXXX:YYYY:d326:143a:2015:79fa(2600:1f16:XXXX:YYYY:d326:143a:2015:79fa) 56 data bytes
^C

近隣要請に対して近隣通知が返ってこず近隣探索に失敗している。

ubuntu1# ip -6 nei
2600:1f16:XXXX:YYYY:d326:143a:2015:79fa dev eth0  INCOMPLETE

結果: 通信不可

管理されているアドレスに近いグローバルユニキャストアドレスをつける

DHCPv6で取れるアドレス (2600:1f16:XXXX:YYYY:f557:112e:f9bd:c7f3) + 1 をつける

ubuntu1# ip -6 addr add 2600:1f16:XXXX:YYYY:f557:112e:f9bd:c7f4/64 dev eth0

ubuntu1 to Internet

ubuntu1# ping6 ipv6.google.com
PING ipv6.google.com(in-in-x8a.1e100.net) 56 data bytes
^C

結果: 通信不可

ubuntu1 to ubuntu2

ubuntu1# ping6 2600:1f16:XXXX:YYYY:d326:143a:2015:79fa
PING 2600:1f16:XXXX:YYYY:d326:143a:2015:79fa(2600:1f16:XXXX:YYYY:d326:143a:2015:79fa) 56 data bytes
From 2600:1f16:XXXX:YYYY:f557:112e:f9bd:c7f4 icmp_seq=1 Destination unreachable: Address unreachable
From 2600:1f16:XXXX:YYYY:f557:112e:f9bd:c7f4 icmp_seq=2 Destination unreachable: Address unreachable
^C

結果: 通信不可

グローバルユニキャストアドレス(ULAを含む)はユーザが勝手持込IPv6アドレスを付けられない様子。

リンクローカルユニキャストアドレス

ubuntu1 のリンクローカルアドレスとして手動で fe80::1234 を付ける

ubuntu1# ip addr del fe80::4df:a5ff:fe6c:5d57/64 dev eth0
ubuntu1# ip addr add fe80::1234/64 dev eth0

ubuntu2のリンクローカルアドレスへICMP ECHO requestを飛ばすが返事はない。ubuntu2の近隣探索にも失敗している。

ubuntu1# ping6 fe80::4f0:13ff:feeb:c61d%eth0
PING fe80::4f0:13ff:feeb:c61d%eth0(fe80::4f0:13ff:feeb:c61d) 56 data bytes
From fe80::1234 icmp_seq=1 Destination unreachable: Address unreachable
From fe80::1234 icmp_seq=2 Destination unreachable: Address unreachable
^C

ubuntu1# ip -6 nei
fe80::4f0:13ff:feeb:c61d dev eth0  INCOMPLETE

リンクローカルアドレスも勝手アドレスを付けらず、インフラ(仮想スイッチ)がアドレス(/128)単位でアクセス制限をしているようである。個々のインスタンスを管理するためにstateful DHCPv6を使うのが合理的であるし、ネットワークも割り当てたIPv6アドレスでない勝手IPv6アドレスによる通信を抑止しているようだ。

関連記事

■ Amazon EC2 VPCのIPv6対応 インスタンスへのIPv6アドレス付与は m-flagつきRA + stateful DHCPv6
http://qiita.com/ip6/items/5c307af204ea83097755

続きを読む

無料で使えるSSL – 「Let’s Encrypt」をh2oに設定してhttp2.0に対応してみた

2014年11月にElectronic Frontier Foundation、Mozilla、Cisco Systems、ミシガン大学などが共同で立ち上げた「Let’s Encrypt」。最近では、GoogleがSSLを推奨しており、サイトをSSL対応しておかないと検索順位に影響すると言われています。そんな中、Let’s Encryptは無料で使えるということもあり、導入しているサイトも増えてきています。個人でSSLを導入してhttp2.0対応するにはちょうど良いですね。

ここでは、「Let’s Encrypt」をインストール&h2oに設定してhttp2.0に対応させる方法を説明します。

インストールに使用した環境

Amazon Linux AMI release 2016.09
h2o 2.1.0

h2oがインストールされており、80番ポート、443番ポートともに通信可能になっていることが前提となります。ファイアウォールで80、443が遮断されているとインストールできませんのでご注意下さい。

インストール手順

ソースコード取得

Let’s Encryptのソースコードをgithubのリポジトリから取得してきます。
以下の例では、ホームディレクトリにcloneしていますが、場所はどこでもかまいません。

cd ~
git clone https://github.com/letsencrypt/letsencrypt

インストール

letsencrypt-autoというコマンドが用意されているのでこれを使用します。
必要なパッケージ類を一通りインストールしてくれます。
rootユーザーで実行する必要がありますので、sudoをつけましょう。

cd ./letsencrypt
sudo ./letsencrypt-auto --debug --help

実行中に
「Installing Python packages…」でしばらく止まります。少し待ちましょう。。
以下のようなメッセージが表示されたらインストール完了です。

Installation succeeded.

  letsencrypt-auto [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ...

Certbot can obtain and install HTTPS/TLS/SSL certificates.  By default,
it will attempt to use a webserver both for obtaining and installing the
cert. The most common SUBCOMMANDS and flags are:

obtain, install, and renew certificates:
    (default) run   Obtain & install a cert in your current webserver
    certonly        Obtain or renew a cert, but do not install it
    renew           Renew all previously obtained certs that are near expiry
   -d DOMAINS       Comma-separated list of domains to obtain a cert for

  --apache          Use the Apache plugin for authentication & installation
  --standalone      Run a standalone webserver for authentication
  --nginx           Use the Nginx plugin for authentication & installation
  --webroot         Place files in a server's webroot folder for authentication
  --manual          Obtain certs interactively, or using shell script hooks

   -n               Run non-interactively
  --test-cert       Obtain a test cert from a staging server
  --dry-run         Test "renew" or "certonly" without saving any certs to disk

manage certificates:
    certificates    Display information about certs you have from Certbot
    revoke          Revoke a certificate (supply --cert-path)
    delete          Delete a certificate

manage your account with Let's Encrypt:
    register        Create a Let's Encrypt ACME account
  --agree-tos       Agree to the ACME server's Subscriber Agreement
   -m EMAIL         Email address for important account notifications

More detailed help:

  -h, --help [TOPIC]    print this message, or detailed help on a topic;
                        the available TOPICS are:

   all, automation, commands, paths, security, testing, or any of the
   subcommands or plugins (certonly, renew, install, register, nginx,
   apache, standalone, webroot, etc.)

証明書発行

次に、letsencrypt-autoコマンドを使って証明書の発行を行います。
パラメータに、h2o.confで設定されているホームディレクトリ、ドメイン名(FQDN)、管理者のメールアドレスを指定します。

sudo ./letsencrypt-auto certonly _
  --webroot -w [h2oホームディレクトリのパス] _
  -d [ドメイン名(FQDN)] _
  -m [管理者のメールアドレス] _
  --agree-tos

コマンドを実行すると、以下のディレクトリに証明書とキーファイルが作成されます。

/etc/letsencrypt/live/[ドメイン名]/fullchain.pem
/etc/letsencrypt/live/[ドメイン名]/privkey.pem

h2o.confの設定

作成された証明書をh2o.confに設定します。
併せてhttpでアクセスがあった場合に自動的にhttpsに301リダイレクトする設定にします。

pid-file: /etc/h2o/pid-file
user: root
access-log: /var/log/h2o/access-log
error-log: /var/log/h2o/error-log
file.index: [ 'index.php', 'index.html' ]

listen: 80
listen:
  port: 443
  ssl:
        # 作成した証明書ファイルを設定
    certificate-file: /etc/letsencrypt/live/[ドメイン名]/fullchain.pem
    key-file:  /etc/letsencrypt/live/[ドメイン名]/privkey.pem

hosts:
    # httpでアクセスがあった場合、httpsに301リダイレクトする
  "[ドメイン名]:80":
    paths:
      "/":
        redirect:
          url: https://[ドメイン名]/
          status: 301

    # httpsでアクセスがあった場合はホームディレクトリへ
  "[ドメイン名]:443":
    paths:
      "/":
        file.dir: [ホームディレクトリ]

h2o.confのテスト

設定ファイルに問題が無いかチェックします。

sudo service h2o configtest

証明書を設定してconfigtestを行うと、証明書ファイルのチェックもしてくれます。
結果の中に以下が表示されていれば、正しく証明書が発行されています。

... 略

/etc/letsencrypt/live/[ドメイン名]/fullchain.pem: good

... 略

/etc/letsencrypt/live/[ドメイン名]/fullchain.pem: good

... 略

configuration OK
                                                           [  OK  ]

h2o再起動

configtestに成功したらh2oを再起動しましょう。

sudo service h2o restart

動作確認

ブラウザからhttpsでアクセスして動作を確認します。
以下のように「保護された通信」と緑色で表示されればOKです。

スクリーンショット 2017-01-15 23.13.59.png

また、httpでアクセスすると、自動的にhttpsにリダイレクトされるかもチェックしておきましょう。

併せてアクセスログを見て、http2.0通信になっているか確認します。

XXX.XXX.XXX.XXX - - [15/Jan/2017:23:19:48 +0900] "GET / HTTP/2" 200 43306 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36"

http2.0で通信されていれば、アクセスログに「HTTP/2」と表示されます。

まとめ

Let’s Encryptを使うことで、コストをかけること無くSSL通信に対応することが出来ます。また、h2o等のサーバに設定することによってhttp2.0にも対応することが出来るのでとても便利です。是非一度お試し下さい。

最後に注意点

Let’s Encryptは他の証明書とは異なり、3ヶ月に1回更新が必要となります。
無料で使える代わりに管理者の所在確認をまめに行う必要があると言ったところでしょうか。。

しかし3ヶ月に1回更新する手間を考えても、無料で使えるというのは大きなメリットだと思います。

続きを読む

ローカル環境でAmazon Linuxをテストする

はじめに

可搬性(ポータビリティ)に立ちふさがる密林、Amazon Linux。担当プロジェクトでもご多分に漏れず、Amazon LinuxをOSとしたシステムを組んでいます。
chefを用いて構成管理(商用環境は、OpsWorks)、Test Kitchen + ServerspecでインフラテストしているがOSはCentOS6.7(packerで生成したVagrant box)…OSが違うのに、何が構成管理か、何が可搬性か。

AWS公式のDockerイメージもリリースされたことですし、Dockerを武器にローコストで可搬性を手に入れることが出来ると思い立ったが吉日。
1営業日くらいで可搬性のあるインフラテスト環境を手に入れることが出来ました :dragon_face:

変更のサマリ

OpsWorks用cookbook ローカル環境用cookbook Test KitchenでプロビジョニングするホストのOS Test Kitchenのドライバ 初回のテスト完了までの所要時間
ビフォー example example_local CentOS6.7 Vagrant 20分程度
アフター example Amazon Linux Docker 5分程度

主たる変更は、kitchen-dockerを導入し、Test KitchenのドライバとしてDockerを採用したことです。
変更により、以下のメリットを享受出来るようになりました。

  • cookbookの統一
  • プロビジョニング対象ホストのOSをOpsWorksと合わせることが出来る
  • 初回テスト時の所要時間の短縮

以下で、詳細を記載していきます。

ビフォー

before.png

  1. exampleアプリケーションを稼働させるためのcookbook(example)を開発する

    • OpsWorksを利用しているので、リポジトリ直下にcookbookを配置する必要がある
  2. example cookbookをTest Kitchenで稼働させるために、example_localを開発する
    • example::defaultをincludeし、attributeを上書きするcookbook
  3. Serverspecでテストコードを開発する
    • Test Kitchenにも対応するので、example_localに配置
  4. Test Kitchenでexample cookbookの動作確認とテストを実施
    • プロビジョニング:bundle exec kitchen converge default-example
    • テスト:bundle exec kitchen verify default-example
  5. テストが通ったら、packerに対応させる
    • packer/example.jsonを開発し、cookbookと一緒にAtlasにアップロード
    • AtlasのpackerでVagrant boxを生成する(リモートビルド)
  6. 開発担当者がAtlasからVagrant boxをダウンロードし、exampleアプリケーションを開発

…だるい

設計し、実装を終えた当初は、堅牢で素晴らしいワークフローだと思ったものです。
このケースの課題は

  • cookbook開発のオーバーヘッドが無視できない

    • cookbookの見通しが悪い。_localって何??
    • Atlasは、日本の日勤帯の時間は、ネットワーク帯域を絞っているのでboxのダウンロードが激重
  • attributeでパッケージ名を上書きしている

    • OSが異なることが諸悪の根源
  • 学習コストが結構かかる

    • chefとServerspecは必要経費だとしても、Test Kitchen、Vagrant、Packer、Atlas….

ゴールデンイメージなVagrant boxを中心に添えたワークフローは、堅牢ですがミドルウェアのアップデートのスピードには着いていくことが難しいというのが個人的な印象です。

アフター

after.png

  1. exampleアプリケーションを稼働させるためのcookbook(example)を開発する

    • OpsWorksを利用しているので、リポジトリ直下にcookbookを配置する必要がある
  2. Serverspecでテストコードを開発する
    • Test Kitchenにも対応するので、example_localに配置
  3. Test Kitchenでexample cookbookの動作確認とテストを実施
    • Test Kitchenのドライバとして、Dockerを指定
    • kitchen-dockerでAmazon LinuxのイメージをPULLし、example cookbookをプロビジョニング
    • プロビジョニング:bundle exec kitchen converge default-example
    • テスト:bundle exec kitchen verify default-example
  4. テストが通ったら、リモートリポジトリにPUSH
  5. OpsWorksのスタックをsetupし、AWS上のインフラをプロビジョニング

cookbook開発だけでなく、アプリケーションのローカル開発環境の見直しも併せて行った(Dockerの導入)ので、かなりシンプルはワークフローとなりました。
メリットをまとめると

  • 同一のOSに対してプロビジョニングし、テスト出来る

    • AWS公式Dockerイメージに対してプロビジョニングした結果をテスト出来る
  • コードベースがシンプルになる

    • example_local cookbookを破棄することが出来る
  • cookbook開発に注力出来る

    • 以前に比べて、学習費用対効果が良い
    • 必要経費(chef、Serverspec)のみで開発出来る

Tips

導入に際してのポイントをコードを交えて説明してみます。

kitchen-dockerの導入

gemのインストール

kitchen-dockerというgemが必要になりますので、Gemfileに追記しましょう。
Kitchen-vagrantは不要となりますので、削除しました。

source "https://rubygems.org"

gem "chef"
gem "berkshelf"
gem "test-kitchen"
gem "kitchen-docker"

Gemfileの編集が終わったらbundlerでインストールします。

bundle install --path ./vendor/bundle

.kitchen.ymlの編集

kitchen-dockerのREADMEを参考に、Test Kitchenの設定ファイルを編集していきます。

provisioner:
  name: chef_solo
  environments_path: ../environments
  solo_rb:
    environment: local

Test KitchenのドライバとしてDockerを指定します。sudoするとdockerコマンドへのパスが見つからない場合が多いかと思うので、use_sudo: falseと指定しておきます。
OpsWorks環境とは異なるattributeがあれば、environmentsとしてJSON形式のファイルにまとめておくことをおすすめします。

platforms:
  - name: amazonlinux-201609
    driver_config:
      platform: rhel
      image: amazonlinux:2016.09

name要素でプロビジョニング対象のホストの名前を指定します。
Amazon Linuxは、Test Kitchenの分類ではRHEL系のディストリビューションとなるので、platform: rhelと指定します。
image要素で、Dockerレジストリから取得したいイメージを指定します。OpsWorks環境のOSバージョンと合わせるため、image: amazonlinux:2016.09と指定します。

suites:
  - name: default
    run_list:
      - recipe[example::amazonlinux-local]
      - recipe[example::default]
    attributes:

テストしたいrecipeをリストします。
amazonlinux-localというレシピについては、後述します。

上記をまとめると、以下の様な.Kitchen.ymlとなります。

---
driver:
  name: docker
  use_sudo: false

provisioner:
  name: chef_solo
  environments_path: ../environments
  solo_rb:
    environment: local

platforms:
  - name: amazonlinux-201609
    driver_config:
      platform: rhel
      image: amazonlinux:2016.09

suites:
  - name: default
    run_list:
      - recipe[example::amazonlinux-local]
      - recipe[example::default]
    attributes:

amazonlinuxの導入

amazonlinuxは、AWS公式のDockerイメージですが、AWS環境と全く同一のものではありません。あくまでも、可搬性の観点で現状取りうる手段の中で最もAWS環境で稼働するAmazon Linuxに近い仮想環境です。
そのため、AWS環境との差異(OSの初期設定含む)については、自分たちで対応する必要があります。
私達のチームでは、差異を埋めるrecipeを開発して対応しました。

# sysconfigファイル
default[:sysconfigs] = ['i18n', 'network']

システム設定ファイル(/etc/sysconfig)の差異をattributeにまとめ、templateとして配置しておきます。

$ tree /path/to/example/example/templates/default/
/path/to/example/example/templates/default/
├── i18n.erb
├── config.erb
└── network.erb
# ローカル開発環境(Amazon LinuxのDockerイメージ)でのレシピ開発のための各種ファイルの配置
node[:sysconfigs].each do |sysconfig|
  template "/etc/sysconfig/#{sysconfig}" do
    owner "root"
    group "root"
    mode 0644
    not_if { File.exist?("/etc/sysconfig/#{sysconfig}") }
  end
end

配置したtemplateを上記の様なrecipeでプロビジョニングしていきます。

# SELinuxは明示的にDisable
include_recipe 'selinux'
template "/etc/selinux/config" do
  owner "root"
  group "root"
  mode 0644
  not_if { File.exist?("/etc/selinux/config") }
end

これは、テストのためのプロビジョニングです。
ServerspecでSELinuxの設定をテストしているのですが、/etc/selinux/configファイルが必須の内容となっておりましたので、ローカル環境でのrecipe開発のためだけにプロビジョニングしています。

# peclを利用するのでコンパイラをインストール
package "gcc"

gccがインストールされておりませんので、テスト対象のrecipeをプロビジョニングする前にインストールしておきます。

上記をまとめると、以下の様なrecipe(amazonlinux-local.rb)となります。
このrecipeをテスト対象のrecipe(example::default)の前にプロビジョニングします(前述の.kitchen.yml参照)。

# Cookbook Name:: example
# Recipe:: amazonlinux-local

# ローカル開発環境(Amazon LinuxのDockerイメージ)でのレシピ開発のための各種ファイルの配置
node[:sysconfigs].each do |sysconfig|
  template "/etc/sysconfig/#{sysconfig}" do
    owner "root"
    group "root"
    mode 0644
    not_if { File.exist?("/etc/sysconfig/#{sysconfig}") }
  end
end

# SELinuxは明示的にDisable
include_recipe 'selinux'
template "/etc/selinux/config" do
  owner "root"
  group "root"
  mode 0644
  not_if { File.exist?("/etc/selinux/config") }
end

# peclを利用するのでコンパイラをインストール
package "gcc"

Test Kitchen

kitchen-dockerの導入を紹介してきましたが、Test Kitchenのコマンド集をまとめておきます。

# cookbookのディレクトリに移動
$ cd /path/to/example/example

# インスタンスの確認
$ bundle exec kitchen list
Instance                    Driver  Provisioner  Verifier  Transport  Last Action  Last Error
default-amazonlinux-201609  Docker  ChefSolo     Busser    Ssh        Verified     <None>

# インスタンスを作成
$ bundle exec kitchen create default-amazonlinux-201609

# インスタンスのセットアップ
$ bundle exec kitchen converge default-amazonlinux-201609

# インスタンスへログイン(tty)
$ bundle exec kitchen login default-amazonlinux-201609
Last login: Thu Jan  5 20:23:42 2017 from 172.17.0.1
[kitchen@685fdd7c1349 ~]$
[kitchen@685fdd7c1349 ~]$ pwd
/home/kitchen

# テスト(serverspec)の実行
$ bundle exec kitchen verify default-amazonlinux-201609

# インスタンスの破棄
% bundle exec kitchen destroy default-amazonlinux-201609

おわりに

OpsWorksを導入して以来、Amazon Linuxをどうテストするかという課題を抱えていましたが、AWS公式のDockerイメージが提供されたことにより、ローコストで可搬性のあるテストを実施出来るようになりました。
今後の課題は、プロビジョニングをCIすることを目標に必要なライブラリの導入や開発、変更を加えて行きたいと思います。
増え続けるcookbookや優秀なchefの育成に困っている開発チームの課題解決の一助となれば幸いです。

参考

続きを読む

AWS RDS for MySQL5.5 => 5.6 アップグレード手順 (CLI) (2017年検証)

AWSから5.5の古いバージョンアップデートするよー。って通知がきたので
手動アップグレードをすることに。

ググッてみたけども、RDSって枯れてるからか、古い情報しかないんですよね。
そこでメモがてらに手順を記載します。

やること

  • 本番稼働しているRDS MySQL 5.5.40b を MySQL 5.6.29にアップグレードする

    • (注意!!)ダウンタイムが数分発生します
  • エンドポイントはそのままでアプリケーション側等の変更は行わない

環境

  • MacOSX ElCapitan (HostOS)

    • 10.11.6

事前準備に必要なもの

  • AWS CLI

    • 入っていない人は何も考えずに pip install awscli と打とう。

参考にしたサイト

全体の流れ

全ての手順を AWS CLI で実行しています。

  • アップグレードしたいRDSインスタンス(Masterインスタンス)にリードレプリカを作成する
  • リードレプリカを作成したら、リードレプリカ側のMySQLをバージョンアップする
  • リードレプリカのインスタンスをマスター昇格させる
    • 厳密にはリード専用ではなく、独立したインスタンスにさせる
    • この時点でマスターインスタンス側がデータが更新されるとデータ不整合が発生します。
  • マスターインスタンスとマスター昇格させたリードレプリカインスタンスのエンドポイントを切り替える。
    • この切り替えの期間がダウンタイム発生時間です。

手順

以下ここから全体の流れの詳細。
作業はHostOS(Mac)から作業しています。

バージョンアップしたいRDSインスタンスの確認

マスターインスタンス名を変数にエクスポート

MASTER_INSTANCE='{DBインスタンス名}'

変数の確認

cat << ETX

        MASTER_INSTANCE ${MASTER_INSTANCE}

ETX

マスターインスタンスの確認

aws rds describe-db-instances --db-instance-identifier ${MASTER_INSTANCE}

マスターインスタンスのMySQLバージョンの確認

aws rds describe-db-instances --db-instance-identifier ${MASTER_INSTANCE} --query 'DBInstances[].EngineVersion' --output text

レスポンス

5.5.40b

マスターインスタンスのリードレプリカを作成

  • 今回は同一AvailabilityZoneに作成しています。
  • AvailabilityZoneの指定をしない場合違うAvailabilityZoneに作成されてしまう可能性がありますので、用途に応じて実行してください。

アップグレードインスタンス名を変数にエクスポート

UPGRADE_INSTANCE='{DBインスタンス名}'

変数の確認

cat << ETX

        UPGRADE_INSTANCE ${UPGRADE_INSTANCE}

ETX

マスターインスタンス側のAvailabilityZoneを確認

AZ=$(aws rds describe-db-instances --db-instance-identifier ${MASTER_INSTANCE} --query 'DBInstances[].AvailabilityZone' --output text)

変数の確認

cat << ETX

        AZ ${AZ}

ETX

リードレプリカを作成する。

実行後、マスターインスタンス側にリードレプリカの設定が走るので多少の負荷がかかります。

リードレプリカの作成に数分かかります。

aws rds create-db-instance-read-replica \
    --db-instance-identifier ${UPGRADE_INSTANCE} \
    --source-db-instance-identifier ${MASTER_INSTANCE} \
    --availability-zone ${AZ}

マスターインスタンス側にリードレプリカが設定されていることの確認

aws rds describe-db-instances --db-instance-identifier ${MASTER_INSTANCE} --query 'DBInstances[].ReadReplicaDBInstanceIdentifiers' --output text

レスポンスが作成したリードレプリカと一致していることを確認

cat << ETX

        `aws rds describe-db-instances --db-instance-identifier ${MASTER_INSTANCE} --query 'DBInstances[].ReadReplicaDBInstanceIdentifiers' --output text` == ${UPGRADE_INSTANCE}

ETX

レスポンス

        {マスター側リードレプリカ設定DBインスタンス名} == {アップグレードDBインスタンス名}

スレーブの同期状態の確認

  • マスターインスタンスに接続できるEC2インスタンスから一旦mysqlコマンドで接続します。
  • Seconds_Behind_Master はスレーブ遅延の秒数です。 0であればスレーブ遅延していません。
mysql -h {アップグレードインスタンスのエンドポイント} -u {ユーザー名} -p --auto-rehash

スレーブのステータスを確認

> SHOW SLAVE STATUS\G

Seconds_Behind_Master: 0 となっていることを確認してください。なっていない場合スレーブ遅延が発生しています。

リードレプリカインスタンス用のパラメーターグループの作成

マスターインスタンスのパラメーターグループファミリーがmysql5.5の為別途パラメーターグループを設定する必要があります。

パラメーターグループを作成しなくてもよい場合は default.mysql5.6 を使用してください。
ただしデフォルトパラメーターグループだとMySQL側の細かな設定を変更できないのでおすすめはしません。

パラメーターグループ名を変数にエクスポート

PARAMETER_GROUP='{任意の名前}'

変数の確認

cat << ETX

        PARAMETER_GROUP ${PARAMETER_GROUP}

ETX

パラメーターグループの作成

aws rds create-db-parameter-group \
    --db-parameter-group-name ${PARAMETER_GROUP} \
    --db-parameter-group-family 'mysql5.6' \
    --description 'mysql5.6 parameter group'

パラメーターグループの確認

aws rds describe-db-parameter-groups \
    --db-parameter-group-name ${PARAMETER_GROUP}

リードレプリカインスタンス側のMySQLバージョンアップ

  • リードレプリカインスタンスのStatusが available になってから作業してください

リードレプリカインスタンスの状態確認

aws rds describe-db-instances --db-instance-identifier ${UPGRADE_INSTANCE}

MySQLのバージョン確認

cat << ETX

        `aws rds describe-db-instances --db-instance-identifier ${MASTER_INSTANCE} --query 'DBInstances[].EngineVersion' --output text` == `aws rds describe-db-instances --db-instance-identifier ${UPGRADE_INSTANCE} --query 'DBInstances[].EngineVersion' --output text`

ETX

レスポンス

        5.5.40b == 5.5.40b

リードレプリカのバージョンアップ

  • --apply-immediately を指定しないと即時反映されません。
  • アップグレードに数分かかります
aws rds modify-db-instance \
  --db-instance-identifier ${UPGRADE_INSTANCE}  \
  --apply-immediately \
  --allow-major-version-upgrade \
  --db-parameter-group-name ${PARAMETER_GROUP} \
  --option-group-name 'default:mysql-5-6' \
  --engine-version 5.6.29

リードレプリカのマスター昇格

コレを実行した時点でマスターインスタンスからのデータ同期は解除されますのでこれ以降の作業は
速やかにやりましょう

 aws rds promote-read-replica \
  --db-instance-identifier ${UPGRADE_INSTANCE} \

リードレプリカインスタンスからリードオンリーのフラグが外れていることの確認

aws rds describe-db-instances \
    --db-instance-identifier ${UPGRADE_INSTANCE} \
    --query 'DBInstances[].StatusInfos' \
    --output text

上記パラメーターで replicating read replication の設定がなくなっていたらOK

マスターインスタンスのエンドポイントの変更

マスターインスタンス側のエンドポイントを先に剥がさないとリードレプリカインスタンスにエンドポイントを付け替えできません。

確認

cat << ETX

       MASTER_INSTANCE ${MASTER_INSTANCE}

ETX

エンドポイントの切り替え

  • 実行後rebootが走ります。
aws rds modify-db-instance \
    --db-instance-identifier ${MASTER_INSTANCE} \
    --new-db-instance-identifier "${MASTER_INSTANCE}-cold-standby" \
    --apply-immediately

リードレプリカインスタンスのエンドポイントの変更

確認

cat << ETX

       UPGRADE_INSTANCE ${UPGRADE_INSTANCE}

ETX
  • 実行後rebootが走ります。
aws rds modify-db-instance \
    --db-instance-identifier ${UPGRADE_INSTANCE} \
    --new-db-instance-identifier "${MASTER_INSTANCE}" \
    --apply-immediately

補足 バージョンアップ失敗時のロールバック手順

何かしらの原因でバージョンアップで動作不調の場合は下記の方法にてロールバックを行います。

  • 切り替え後すぐの動作不調の場合の方法になります
  • 時間がしばらく経過の場合はsnapshotからの復元のほうがいいかと思います

アップグレードしたインスタンスをコールドスタンバイに変更

aws rds modify-db-instance \
    --db-instance-identifier ${UPGRADE_INSTANCE} \
    --new-db-instance-identifier "${UPGRADE_INSTANCE}-cold-stanby" \
    --apply-immediately

元のインスタンスのエンドポイントを変更

aws rds modify-db-instance \
    --db-instance-identifier "${MASTER_INSTANCE}-cold-stanby" \
    --new-db-instance-identifier "${MASTER_INSTANCE}" \
    --apply-immediately

最後に

以上でMySQL 5.5 => 5.6のアップグレード手順になります。
公式のドキュメントで記載していますが、5.6 => 5.7 も同様の手順でできるとは書いてあります。

続きを読む

【メモ】 AWSにkopsを使ってkubernetesのクラスタを構築する

kopsでクラスターをインストールしてみたのでメモしておく

眠い。

元ネタ

http://kubernetes.io/docs/getting-started-guides/kops/

普通に上の記事を見ながらやった方が良い

kubectlのインストール

# 最新が1.5.1だったので1.5.1をインストール
# Linux
wget https://storage.googleapis.com/kubernetes-release/release/v1.5.1/bin/linux/amd64/kubectl
chmod +x kubectl
mv kubectl /usr/local/bin/kubectl

# Macで作業する場合は以下らしい(やってない)
wget https://storage.googleapis.com/kubernetes-release/release/v1.5.1/bin/darwin/amd64/kubectl
chmod +x kubectl
mv kubectl /usr/local/bin/kubectl

kopsのインストール

# Linuxから作業した場合
wget https://github.com/kubernetes/kops/releases/download/v1.4.1/kops-linux-amd64
chmod +x kops-linux-amd64
mv kops-linux-amd64 /usr/local/bin/kops

# Macで作業する場合は以下らしい(やってない)
wget https://github.com/kubernetes/kops/releases/download/v1.4.1/kops-darwin-amd64
chmod +x kops-darwin-amd64
mv kops-darwin-amd64 /usr/local/bin/kops

AWS Cliをインストール/設定しておく

cliで使うユーザの権限でS3とかIAMの作成権限とか必要っぽいのでIAMロールに追加しておく

今回つけておいたポリシー (不要なのもあるかも)

  • AmazonEC2FullAccess
  • AmazonSQSFullAccess (どっかでSQS権限が必要とか見た記憶があるんだけど幻だったかもしれない)
  • IAMFullAccess
  • AmazonS3FullAccess
  • AmazonRoute53FullAccess
curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
sudo python get-pip.py
sudo pip install awscli
aws configure

Route53にkubernetesクラスター用のゾーンを作成

# aws cliが使えるなら以下の感じで作る
aws route53 create-hosted-zone --name dev.example.com --caller-reference 1

S3にクラスターの設定ファイルを置くバケットを作る

# aws cliが使えるなら以下の感じで作る
aws s3 mb s3://clusters.dev.example.com

# 以下の設定をbash_profileあたりに書いて置く
# export KOPS_STATE_STORE=s3://clusters.dev.example.com
vi ~/.bash_profile
source ~/.bash_profile

クラスターの作成

この時点では設定ファイルが出来上がるだけでEC2インスタンスとかは立ち上がらないです

# VPCを指定しないと自動でVPCが作られてそこにインスタンスが配置される
kops create cluster --zones=ap-northeast-1a apnortheast1.dev.example.com
# 既存のVPCを指定する場合はvpcオプションとnetwork-cidrオプションを指定すればOK
# https://github.com/kubernetes/kops/blob/master/docs/run_in_existing_vpc.md
kops create cluster --zones=ap-northeast-1a apnortheast1.dev.example.com --vpc=vpc-xxxxxxx --network-cidr=172.31.0.0/16

クラスターの定義を修正

デフォルトで立ち上げるとそこそこ良いインスタンス作られるので貧乏仕様に変更

# クラスターの設定
# デフォルトのままで問題ないかと。名前が気に入らなかったり、kubernetesのバージョンとか変えたかったら編集
kops edit cluster apnortheast1.dev.example.com

# master用インスタンスの設定
# なんか自動でmaster-zone名で名前ついてる
# machineTypeを好きなインスタンスタイプに変える
# おそらくmaxSize/minSizeでmasterのインスタンス数を制御できる
# イメージはAMI IDを指定しても大丈夫。デフォルトだとDebian(jessie)だったけど、ami-eec1c380とか指定すればCentOS7で作成される
# https://github.com/kubernetes/kops/blob/master/docs/images.md
kops edit ig --name=apnortheast1.dev.example.com master-ap-northeast-1a

# node用インスタンスの設定
# マスター用と同じノリ
kops edit ig --name=apnortheast1.dev.example.com nodes

クラスター情報の更新

# 設定ファイルだけ反映
kops update cluster apnortheast1.dev.example.com

# 問題なければ --yesをつけて実行するとインスタンスとか作られる
# ちなみにVPCは自動的に"apnortheast1.dev.example.com"で作成されている
# networkCIDRが一致してるVPCがあったらそこに作ってくれるのかな?
# -> 20170111追記 create時に指定すればVPCを指定できた。createのとこにコマンド追記。後からは変えられないっぽい
kops update cluster apnortheast1.dev.example.com --yes

API用のDNSレコードができてないバグ

https://github.com/kubernetes/kops/issues/859

v1.5で修正されるかな

sshログインしてみる

コンソールで確認するとパブリックIPが付与されているので~/.ssh/id_rsaを使ってssh接続できる

# デフォルトで~/.ssh/id_rsa.pubを使って鍵交換してくれるっぽい
# なので-iで指定しなくても一緒
ssh -i ~/.ssh/id_rsa $publicIP
# kubectlのバージョン確認
kubectl version
# ノードの確認
kubectl get nodes
NAME                                               STATUS    AGE
ip-172-20-46-247.ap-northeast-1.compute.internal   Ready     1h
ip-172-20-51-144.ap-northeast-1.compute.internal   Ready     1h
ip-172-20-61-100.ap-northeast-1.compute.internal   Ready     1h

続きを読む

AWS IoTをPythonで簡単に始めるまで

はじめに

https://aws.amazon.com/jp/iot/

Amazon Web Serviceの比較的新しいサービスであるAWS IoTですが、出始めということで日々進化しています。デバイスはなくともMacとPythonを使ってAWS IoTを体験していきたいと思います。

AWS Consoleでのセットアップ

Amazon Web ServiceのコンソールでAWS IoTを選択し、Connectのメニューから”Configuring a device”を選択します。

スクリーンショット 2017-01-08 11.42.04.png

Platformとして”Linux/OSX”を選択し、Pythonを選択します。

スクリーンショット 2017-01-08 11.42.40.png

Thingの名前はなんでもかまいませんが、ここでは”test_thing”にしました。”show optional configuration (this can be done later)”を選択するとThingにタイプや属性を付加できます。これは、後からThingを探しやすくするものですが、まずは必要ありません。

スクリーンショット 2017-01-08 11.45.07.png

Thingの名前だけ設定するとそれに合わせて、クライアント証明書及びポリシーが作成されます。ここで作成されたクライアント証明書を用いれば、AWS IoTの機能をPythonアプリケーションからアクセスが可能となります。

“Linux/OSX”ボタンを押すとクライアント証明書や秘密鍵などの情報がダウンロードされます。

スクリーンショット 2017-01-08 11.45.51.png

Pythonアプリケーション

ダウンロードしたzipファイルの後の処理は、以下のような形になります。

スクリーンショット 2017-01-08 11.46.22.png

私の環境では、./start.shでPermissionエラーになりました。サンプルの中で必要なライブラリをインストールしているもようなのですが、sudoをつけて再度実行したところ成功しました。

$ cd aws-iot-device-sdk-python/
$ sudo python setup.py install

トラブルシューティング

もう一度start.shを使ってサンプルアプリを実行してみました。内部では、以下のようなコマンドでクライアント証明書、ルート証明書、秘密鍵を設定して実行しています。

python aws-iot-device-sdk-python/samples/basicPubSub/basicPubSub.py -e XXXXXXXX.iot.ap-northeast-1.amazonaws.com -r root-CA.crt -c test_thing.cert.pem -k test_thing.private.key

しかし残念ながら以下のようなエラーが発生しました。

ssl.SSLError: [SSL: UNKNOWN_PROTOCOL] unknown protocol (_ssl.c:590)

OpenSSLのバージョンが古いような感じなので、バージョンを変更してみました。
http://ytooyama.hatenadiary.jp/entry/2016/06/23/004429
https://teratail.com/questions/47299
http://stackoverflow.com/questions/35473033/how-to-fix-openssl-error-with-aws-cli-iot-api

動作確認

もう一度start.shを実行するとPythonアプリが以下のようなログメッセージを数秒に一度sdk/test/Pythonのtopicにメッセージの送受信を行う。

2017-01-08 16:54:54,102 - AWSIoTPythonSDK.core.protocol.mqttCore - DEBUG - Try to put a publish request 178 in the TCP stack.
2017-01-08 16:54:54,102 - AWSIoTPythonSDK.core.protocol.mqttCore - DEBUG - Publish request 178 succeeded.
Received a new message: 
New Message 176
from topic: 
sdk/test/Python
--------------

AWS IoTのダッシュボードで確認すると、以下のようにグラフが出力される。

スクリーンショット 2017-01-08 17.02.36.png

おわりに

デバイスがなくてもMacとPythonアプリだけでデバイスのエミュレーションができるので非常に便利です。AWS IoTがますます便利になっていますね。

続きを読む