絶対的に使った方がいいLogstashのMultiple Pipelinesについて書いてみた

はじめに

おはです!
Logstashのフィルタの中でもGrokが好きなぼくが、Advent Calendar11日目を書かせていただきますー
あ、でも今回は、Grokについては書かないですよ!

じゃあ、何書くの?Grokしか脳のないお前が何を書くのさー
そりゃ、あれだよ!Logstash 6.0がGAされたので、待ちに待ったMultiple Pipelinesについて書くしかないでしょ!

てことで、LogstashのMultiple Pipelinesについて、ゆるーく書いていきます( ゚Д゚)ゞビシッ

構成について

今回テストするにあたって使用した構成は以下です。

  • Amazon Linux AMI 2017.09.1 (HVM)
  • Logstash 6.0
  • logstash-input-s3
  • Elasticsearch 6.0
  • Kibana 6.0
  • X-Pack 6.0

ちなみに、もろもろインストールされている前提で記載しています。
もし、インストールする場合は、以下のインストール手順を参考にして頂ければと思います。

Logstashについて

Logstashは、Elasticsearch社が提供するオープンソースのデータ収集管理ツールです。

LogstashのPipelineは、以下のような流れで処理されます。
例として、インプットデータをApacheのログファイルで、ログファイルに対してフィルタをかけ、Elasticsearchにストアするといった流れにしてます。1

logstash01.png

INPUT

様々なデータソースを取り込みたい!そんな要望に応えるべく用意されたのがLogstash。
Logstashは、様々なデータ形式に対応しています。
例えば、ソフトウェアのログ、サーバのメトリクス、Webアプリケーションのデータや、クラウドサービスなど。

FILTER

INPUTしたデータソースをフィルタで解析し、構造化します。
データソースの変換には、正規表現でデータをパースするためのGrokフィルタや、IPアドレスから地理情報を得るためのGeoIPフィルタなど様々なフィルタライブラリが用意されています。

OUTPUT

データを構造化したのち、任意の出力先にデータをストアします。
Elasticsearch以外の出力先も多数提供されているので、環境に合わせてデータをストアします。

Logastashのディレクトリ構成

上記までが処理の流れで、これらの処理を定義するファイルをLogstashでは準備する必要があります。

以下のようにLogstashのディレクトリは構成されており、conf.d配下に定義ファイル(hoge.confと記載)を配置します。

/etc/logstash
  ├ conf.d
  │ └ hoge.conf
  ├ jvm.options
  ├ log4j2.properties
  └ logstash.yml

hoge.confに様々なデータソースに対して定義します。
例えば、AWSのALBのアクセスログとApacheのアクセスログを定義すると以下のようになります。2

hoge.conf
input {
  s3 {
    tags => "alb"
    bucket => "hoge"
    region => "ap-northeast-1"
    prefix => "hoge/"
    interval => "60"
    sincedb_path => "/var/lib/logstash/sincedb_alb"
  }
  file {
    path => "/etc/logstash/log/httpd_access.log"
    tags => "httpd"
    start_position => "beginning"
    sincedb_path => "/var/lib/logstash/sincedb_httpd"
  }
}
filter {
  if "alb" in [tags] {
    grok {
      patterns_dir => ["/etc/logstash/patterns/cloudfront_patterns"]
      match => { "message" => "%{ALB_ACCESS}" }
      add_field => { "date" => "%{date01} %{time}" }
    }
    date {
      match => [ "date", "yy-MM-dd HH:mm:ss" ]
      locale => "en"
      target => "@timestamp"
    }
    geoip {
      source => "c_ip"
    }
    useragent {
      source => "User_Agent"
      target => "useragent"
    }
    mutate {
      convert => [ "time_taken", "float" ]
      remove_field => [ "message" ]
    }
  else if "httpd" in [tags] {
    grok {
      patterns_dir => ["/etc/logstash/patterns/httpd_patterns"]
      match => { "message" => "%{HTTPD_COMMON_LOG}" }
    }
    geoip {
      source => "clientip"
    }
    date {
      match => [ "date", "dd/MMM/YYYY:HH:mm:ss Z" ]
      locale => "en"
      target => "timestamp"
    }
    mutate {
      remove_field => [ "message", "path", "host", "date" ]
    }
  }
}
output {
  if "alb" in [tags] {
    elasticsearch {
      hosts => [ "localhost:9200" ]
      index => "elb-logs-%{+YYYYMMdd}"
    }
  }
  else if "httpd" in [tags] {
    elasticsearch {
      hosts => [ "localhost:9200" ]
      index => "httpd-logs-%{+YYYYMMdd}"
    }
  }
}

このようにデータソース毎にタグを付与し、if文で判定させるといったかたちになってます。
今回は、データソースが少ないからいいですが、更に増やしていくとなると可読性も悪くなるのと、リソースのハンドリングも難しくなってきます。
また、データソースが増えたり、フィルタ変更などの際には、一つの定義ファイルを更新するため、全体に影響を及ぼす可能性があります。。
なんてこった(´□`;)

Multiple Pipelinesになると何がいいのさ

そこで!Multiple Pipelinesの出番なのです!
hoge.confに対して複数のデータソースを組み込んでいたものを、分割することができちゃうのですー
また、リソースの割り当てとして、Worker数などもPipeline毎に割り当てることができるのです!歓喜!!

ここからは、Multiple Pipelinesをどのように使うのかを書いてきます。

Multiple Pipelinesを試してみる。

Logstashのディレクトリ構成は変わらないのですが、新しくpipelines.ymlという定義ファイルを作成します。
また、先ほどのhoge.confをデータソース毎にファイルを以下のように分けます。

  • alb.cfg
  • httpd.cfg

alb.cfgの定義は以下です。

alb.cfg
input {
  s3 {
    bucket => "hoge"
    region => "ap-northeast-1"
    prefix => "hoge/"
    interval => "60"
    sincedb_path => "/var/lib/logstash/sincedb_alb"
  }
}
filter {
  grok {
    patterns_dir => ["/etc/logstash/patterns/cloudfront_patterns"]
    match => { "message" => "%{ALB_ACCESS}" }
    add_field => { "date" => "%{date01} %{time}" }
  }
  date {
    match => [ "date", "yy-MM-dd HH:mm:ss" ]
    locale => "en"
    target => "@timestamp"
  }
  geoip {
    source => "c_ip"
  }
  useragent {
    source => "User_Agent"
    target => "useragent"
  }
  mutate {
    convert => [ "time_taken", "float" ]
    remove_field => [ "message" ]
  }
 }
output {
  elasticsearch {
    hosts => [ "localhost:9200" ]
    index => "elb-logs-%{+YYYYMMdd}"
  }
}

httpd.cfgの定義は以下です。

httpd.cfg
input {
  file {
    path => "/etc/logstash/log/httpd_access.log"
    start_position => "beginning"
    sincedb_path => "/var/lib/logstash/sincedb_httpd"
  }
}
filter {
  grok {
    patterns_dir => ["/etc/logstash/patterns/httpd_patterns"]
    match => { "message" => "%{HTTPD_COMMON_LOG}" }
  }
  geoip {
    source => "clientip"
  }
  date {
    match => [ "date", "dd/MMM/YYYY:HH:mm:ss Z" ]
    locale => "en"
    target => "timestamp"
  }
  mutate {
    remove_field => [ "message", "path", "host", "date" ]
  }
}
output {
  elasticsearch {
    hosts => [ "localhost:9200" ]
    index => "httpd-%{+YYYYMMdd}"
  }
}

ディレクトリ構成は以下になります。

/etc/logstash
  ├ logstash.yml
  ├ conf.d
  │ └ alb.cfg
  │ └ httpd.cfg
  ├ jvm.options
  ├ log4j2.properties
  └ pipelines.yml

ここでやっと登場するpipelines.ymlの定義は以下です。

pipelines.yml
- pipeline.id: alb
  pipeline.batch.size: 125
  path.config: "/etc/logstash/conf.d/alb.cfg"
  pipeline.workers: 1
- pipeline.id: httpd
  pipeline.batch.size: 125
  path.config: "/etc/logstash/conf.d/httpd.cfg"
  pipeline.workers: 1

めっちゃシンプルですね。
呼び出すファイルパスの指定とパラメータの定義を記載するだけです。
データソース単位でpipeline.workersを割り当てられることになったので、柔軟にコアの配分ができるようになりました。
詳細の設定については、settings fileを確認してもらえればと思います。

動かすよ!

今回、サービス起動を前提としているため、pipelines.ymlを読み込ませるには、logstash.confのpath.configをコメントアウトする必要があります。
(ここでハマりました。。公式サイトにサービス起動について書かれているところがみつからず。。)

logstash.conf
# path.config: /etc/logstash/conf.d/*.conf

てことで、起動しますー
これでデータソース単位で動かすことができます。

$ initctl start logstash
logstash start/running, process 3121

おまけ

今回説明していないですが、X-Packを導入することで、MonitoringでPipelineの状況をみることができます。
データの流れを把握したり、分岐などのロジックが有効に働いてるかなども確認することが可能です。

先ほど、alb.cfgを取り込んだ際のPipelineは以下の様に表示されます。

logstash03.png

さいごに

いかがでしたか?
Multiple Pipelinesは、常にデータを取り込んでいるLogstashを支えるための根幹たる機能ではないでしょうか?
ぜひぜひ、みなさんもMultiple Pipelinesを使って、よりよいLogstsah Lifeを送って頂ければとヽ(*゚д゚)ノ

それでは、Advent Calendar11日目を終わりますー
明日の12日目は、”Elasticsearch v1.7 -> v2.4 -> v5.5 と段階的にバージョンアップした話し”ですね!
楽しみだすー


  1. Elasticsearch社の公開されているグローバルIPを利用しています 

  2. 指定しているパスは、環境に合わせて指定してください 

続きを読む

TerraformでAWS AMIの最新を常に使うようにする

TerraformとAWSに同時入門する
の続きで、

最新のAMIが常に指定されるようなami設定にする

を行えるようにします。

確認環境

$ terraform version
Terraform v0.11.1
+ provider.aws v1.5.0

取得するAMIのスペック

今回は2017/12/10時点でのAmazon Linuxの下記スペックにおける最新AMI ID(ami-da9e2cbc)を取得します。
最新AMI IDはこちらで確認できます: Amazon Linux AMI ID

  • リージョン: アジアパシフィック東京
  • 仮想化タイプ: HVM
  • ルートデバイスタイプ: EBS-Backed
  • アーキテクチャ: x86_64
  • ボリュームタイプ: gp2

:warning: 注意点
AMI IDはリージョン毎に異なるようなので複数リージョンにまたがった環境の場合は注意が必要かもしれません

結論

簡易版

フィルタ条件はAMI Image名の条件のみ

aws_ami.tf
data "aws_ami" "amazon_linux" {
  most_recent = true
  owners = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn-ami-hvm-*-x86_64-gp2"]
  }
}

詳細版

フィルタ条件として今回の指定スペックをすべて指定

参考: Terraformでもいつでも最新AMIからEC2を起動したい

aws_ami.tf
data "aws_ami" "amazon_linux" {
  most_recent = true
  owners = ["amazon"]

  filter {
    name   = "architecture"
    values = ["x86_64"]
  }

  filter {
    name   = "root-device-type"
    values = ["ebs"]
  }

  filter {
    name   = "name"
    values = ["amzn-ami-hvm-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  filter {
    name   = "block-device-mapping.volume-type"
    values = ["gp2"]
  }
}

EC2側の設定

ec2.tf
resource "aws_instance" "web-server" {
  ami                    = "${data.aws_ami.amazon_linux.id}"
  instance_type          = "t2.micro"
}

確認

$ terraform plan

  + aws_instance.web-server
      id:                           <computed>
      ami:                          "ami-da9e2cbc"
      ...

AWS CLIでAmazon Linux AMI image名を取得してみる

準備

AWS Command Line Interface のインストール

簡易版のフィルタ条件の説明

AWS CLIで最新のAmazon LinuxのAMI IDを取得する
上記でのシェルを参考に今回取得したい条件に変更します

get-aws-ec2-image.sh.sh
...

describe_images(){
    echo $timestamp > $timestamp_file
    aws ec2 describe-images 
-       --owners self amazon 
+       --owners amazon 
        --filters 
+         Name=name,Values="amzn-ami-hvm-*" 
          Name=virtualization-type,Values=hvm 
          Name=root-device-type,Values=ebs 
          Name=architecture,Values=x86_64 
-         Name=block-device-mapping.volume-type,Values=standard
+         Name=block-device-mapping.volume-type,Values=gp2
}

...

実行結果

$ zsh ./get-aws-ec2-image.sh

amzn-ami-hvm-2014.03.2.x86_64-gp2: ami-df470ede
amzn-ami-hvm-2014.09.0.x86_64-gp2: ami-45072844
amzn-ami-hvm-2014.09.1.x86_64-gp2: ami-4585b044
amzn-ami-hvm-2014.09.2.x86_64-gp2: ami-1e86981f
amzn-ami-hvm-2015.03.0.x86_64-gp2: ami-cbf90ecb
amzn-ami-hvm-2015.03.1.x86_64-gp2: ami-1c1b9f1c
amzn-ami-hvm-2015.09.0.x86_64-gp2: ami-9a2fb89a
amzn-ami-hvm-2015.09.1.x86_64-gp2: ami-383c1956
amzn-ami-hvm-2015.09.2.x86_64-gp2: ami-59bdb937
amzn-ami-hvm-2016.03.0.x86_64-gp2: ami-f80e0596
amzn-ami-hvm-2016.03.1.x86_64-gp2: ami-29160d47
amzn-ami-hvm-2016.03.2.x86_64-gp2: ami-6154bb00
amzn-ami-hvm-2016.03.3.x86_64-gp2: ami-374db956
amzn-ami-hvm-2016.09.0.20160923-x86_64-gp2: ami-1a15c77b
amzn-ami-hvm-2016.09.0.20161028-x86_64-gp2: ami-0c11b26d
amzn-ami-hvm-2016.09.1.20161221-x86_64-gp2: ami-9f0c67f8
amzn-ami-hvm-2016.09.1.20170119-x86_64-gp2: ami-56d4ad31
amzn-ami-hvm-2017.03.0.20170401-x86_64-gp2: ami-859bbfe2
amzn-ami-hvm-2017.03.0.20170417-x86_64-gp2: ami-923d12f5
amzn-ami-hvm-2017.03.1.20170617-x86_64-gp2: ami-bbf2f9dc
amzn-ami-hvm-2017.03.1.20170623-x86_64-gp2: ami-3bd3c45c
amzn-ami-hvm-2017.03.1.20170812-x86_64-gp2: ami-4af5022c
amzn-ami-hvm-2017.03.rc-0.20170320-x86_64-gp2: ami-be154bd9
amzn-ami-hvm-2017.03.rc-1.20170327-x86_64-gp2: ami-10207a77
amzn-ami-hvm-2017.09.0.20170930-x86_64-gp2: ami-2a69be4c
amzn-ami-hvm-2017.09.1.20171103-x86_64-gp2: ami-2803ac4e
amzn-ami-hvm-2017.09.1.20171120-x86_64-gp2: ami-da9e2cbc
amzn-ami-hvm-2017.09.rc-0.20170913-x86_64-gp2: ami-d424e7b2

最新AMI ID(ami-da9e2cbc)が取得できているのがわかります。

amzn-ami-hvm-2017.09.1.20171120-x86_64-gp2: ami-da9e2cbc

取得結果からわかるようにImage名にはスペック名も含まれていることがわかります。

よって今回のスペックのAMI IDはImage名でのフィルタ条件のみで取ることができるため、簡易版ではImage名の値が"amzn-ami-hvm-*-x86_64-gp2"とするフィルタ条件1つで最新のAMI IDを取得していました。

また、aws_ami.tfではmost_recent = trueという設定により取得した中で最新のAMI IDが取得されます。

:warning: Image名の命名規則が変更された場合に指定スペックの最新が取得できなくなるので注意ください

フィルタ条件をnameのみにしてAWS CLIでも確認

AWS CLI側でも一応確認

get-aws-ec2-image.sh
describe_images(){
    echo $timestamp > $timestamp_file
    aws ec2 describe-images 
        --owners amazon 
        --filters 
          Name=name,Values="amzn-ami-hvm-*-x86_64-gp2" 
-          Name=virtualization-type,Values=hvm 
-          Name=root-device-type,Values=ebs 
-          Name=architecture,Values=x86_64 
-          Name=block-device-mapping.volume-type,Values=gp2
}
$ zsh ./get-aws-ec2-image.sh | grep ami-da9e2cbc

amzn-ami-hvm-2017.09.1.20171120-x86_64-gp2: ami-da9e2cbc

最新AMI ID(ami-da9e2cbc)が取得できているのがわかります。

その他の参考

続きを読む

17/12 千代田区/AWSなど】大手衣料系小売業のAWS環境構築支援

職種, SE. 場所, 千代田区. 必要スキル, ・コミュニケーションスキル・1人称で以下のOS/MWの設計・構築・試験ができること -OS : Amazon Linux / RHEL7 -WEB: Apache / Nginx -AP : Tomcat -DB : PostgreSQL. ・AWSの各サービスの概念理解(特にIAM) ・未経験の技術や製品に積極的に取り組める方. 期間, 11月~2018 … 続きを読む

AWSのインスタンスにLAMP環境を構築する際に使用したコマンドについて解説する

AWSにインスタンスを作成したあとに・・・

AWSにインスタンスを作成したあと、SSHのキーを使ってインスタンスに入るところから解説します。

使用するインスタンス

  • 無料枠のEC2
  • OSはAmazon Linux
  • セキュリティグループはSSH

インスタンスができたら

使用する端末がwinの場合はツールをインストールしてください。macの場合はターミナルを起動してください。
macのターミナルの場所:アプリケーション>ユーティリティ>ターミナル

1インスタンスに入る

①SSHのキーの設定

インスタンス作成の際にダウンロードしたキーを使用します。
chmod 600 ~/hoge/hoge.pem
⇨このキーの権限を設定するよ!
【入力内容】
:sunny:~/hoge/hoge.pem のところには
 ダウンロードしたキーのファイルパスを入力してください。

【コマンドの解説】
:cherry_blossom: chmod
チェンジモードchange modeの意味でアクセス権を変更するときに使用します。

:cherry_blossom: 600
3桁の数字はアクセス権を示します。

600:1桁目は所有者の権限です。
600:2桁目はグループの権限です。
600:3桁目はその他の権限です。

さらにそれぞれの数字に権限の意味があります。
6:読み込み権限と書き込み権限
0:権限なし

つまり600というのは、
所有者の権限には読み込みと書き込みの権限を与え、
グループの権限とその他の権限には権限を何も与えない
ということになります:astonished:

:cherry_blossom: キーのファイルパス
権限を与える対象のファイルを指定することになります。

【参考サイト】
chmodについて詳しく!
chmod? chown? よくわからんって人のための、ファイル権限系まとめ
権限の数字について詳しく!
【 chmod 】 ファイルやディレクトリのアクセス権を変更する
コマンド操作を楽ラクにしたい!
ブクマ必至!Linuxコマンド一覧表【全33種】 2.2 覚えておくと便利なショートカットキー

②SSHのキーを使用して入る

①で使用したキーをここでも使用します。
ssh ec2-user@hoge -i ~/hoge/hoge.pem
⇨このキーでインスタンスに入るよ!
【入力内容】
:sunny:ec2-user@hoge のhogeにはインスタンスのIPv4 パブリック IPを入力してください。
:sunny:~/hoge/hoge.pem のところには①同様、
 ダウンロードしたキーのファイルパスを入力してください。

【コマンドの解説】
:cherry_blossom: ssh
インスタンス作成時のセキュリティグループでタイプSSHを選択しました。
それです。

:cherry_blossom: ec2-user@hoge
アクセス先を指定する。

:cherry_blossom: -i
informationのiです。付加情報がある際にはこのあとに記述します。

:cherry_blossom: ~/hoge/hoge.pem
今回の付加情報です。
「このキーでインスタンスに入るよ!」の「このキー」というのが付加情報になります。

③質問されるので答える

②を実行すると以下の文章が表示されます。

Are you sure you want to continue connecting (yes/no)?

⇨接続することは同意ですか?

同意なので
yes
と入力してください。

④入れた!

以下のAAが表示されたらインスタンスに入れました!おめでとう:heart_eyes:

  __|  __|_  )
  _|  (     /   Amazon Linux AMI
 ___|___|___|

2環境を整える

①インスタンスを更新する

インスタンスを最新の状態にしたいので、アップロードするものがあればアップロードするようにします。
sudo yum update -y
⇨管理者権限でアップデートするよ!
これを実行するとズラズラ文章が流れていきます。

【コマンド解説】
:cherry_blossom: sudo
superuser do の略で、管理者権限で実行することを意味します。
これを入れ忘れると、データが保存されなかったり、
実行しても権限がないと言われてしまうので、入れ忘れに注意してください。
superuserはrootのことです。

:cherry_blossom: yum update
yumはパッケージを取得してそれをどうするかの指定です。
どうするかは今回はupdateなので更新します。
つまりupdateのところをinstallにすれば、パッケージのインストールができます。

:cherry_blossom: -y
何か質問されたらyesで答えるときに使用します。
毎回質問に対して返事するのが面倒なときに使うと便利です。

【参考サイト】
rootとは?
【完全初心者向け】Linuxのrootユーザとは?

②Apache,PHP,MySqlをインストールする

LAMP環境と言われるAMPの部分です。
ちなみにLは(Amazon) LinuxのLです。
sudo yum install -y httpd24 php70 mysql56-server php70-mysqlnd
⇨管理者権限でインストールするよ!
インストールするものは
・Apache
・PHP
・MySql
・PHPのMySql用ドライバー
だよ!

これを実行するとズラズラ文章が流れていきます。

Complete!

が表示すれば成功です。
【入力内容】
:sunny: 数字はバージョンを表しています。インストールするときによって
 使用するバージョンが異なるのでチェックしてください。

【コマンド解説】
:cherry_blossom: sudo yum install -y
詳細は前述済みです。
何をインストールするかの指定を-y以降に記述します。

:cherry_blossom: httpd24
Apache2.4をインストールします。
Apacheとはwebサーバーのことです。
webサーバーがないとPHPなどのプログラムが動かないので必要です。

:cherry_blossom: php70
今回の主役、PHPです。PHP7.0をインストールします。

:cherry_blossom: mysql56-server
今回使用するデータベースはMySqlです。MySql5.6のサーバーの方をインストールします。
サーバーの方と言うだけあって、クライアント(端末)の方もあります。
今回はインスタンス(サーバー)に入れたいので、サーバーの方のMySqlをインストールします。

:cherry_blossom: php70-mysqlnd
PHPでMySqlを使うためのドライバーをインストールします。
これがないとPHPでMySqlを使うことができないです。

サーバーを起動する

力尽きたので後日書きます。

続きを読む

なんという悲しい結末。もうちょっとがんばれAWS – tmatsuuのコメント / はてなブックマーク

テクノロジー · Amazon, Clear, Debian, Gentoo, Red Hat, SUSE & … tmatsuuのコメント. Twitterでシェア · Facebookでシェア; ブックマークする. AWS EC2上で最もパフォーマンスが良いLinuxディストリビューションは?残念ながらAmazon Linuxに優位性は見られない。なんという悲しい結末。もうちょっとがんばれAWS. 続きを読む

AWS(EC2) で Python3 + Flask を Apache で動かす(mod_wsgi?)

はじめに

簡単なWebサービス新しく立ち上げるにあたり、勉強を兼ねて Python を使うことにしたので、その環境構築用のメモとして残す。ほとんど、他の記事を寄せ集めただけなのだけど、mod_wsgiのインストールで少し手間取ったので念のため。

参考:PythonのWebフレームワーク4種比較
https://qiita.com/Morio/items/8db3c9b3ba7f2c71ef27

AWS (EC2) + Apache2

下記のサイトを参考にしてテスト用のEC2サーバのインスタンスを作成後、Apache2 をインストール・起動します。なお、現時点(2017/12/06)でのバージョンは、2.2.34だった。

参考:AWS EC2でWebサーバーを構築してみる
https://qiita.com/Arashi/items/629aaed33401b8f2265c

Python3 + pip3

下記のサイトを参考にして Python3 をインストールし、pip を設定。現時点(2017/12/06)では、python3.6がリリースされているので、3.5ではなく3.6をインストール。

参考:Amazon Linux (EC2)上でPython3と…
https://qiita.com/KeijiYONEDA/items/f9cf37cfc359aa893797
※「3.5」は「3.6」に、「35」は「36」に読み替え

実際に実行したコマンド.
sudo yum install python36-devel python36-libs python36-setuptools
sudo /usr/bin/easy_install-3.6 pip

Flask + mod-wsgi

Flask のインストールは簡単。下記のサイトの最初の5分だけを実行すれば、Hello Flask! を表示するWebサイトは完成!

参考:PythonのFlaskを初めて触ってから30分で…
https://qiita.com/yoshizaki_kkgk/items/3cd785b4a670deec0685
※ 環境構築からHello Flask!まで(5分)だけを実行

・・・でも今回は Apacheサーバを利用するので、mod_swgi のインストールが必要となる。だけど、上記サイトの次の10分以降に書いてあるようにソースから configure・make なんて 前時代的 というか 面倒くさい というか、難しいことは避けたいので、pipに頼ることにする

pip3 install mod-wsgi

このコマンドでインストールできそうなのだけど、下記のエラーが出て前に進まなくなった。apxs って何さ?

Collecting mod_wsgi
  Using cached mod_wsgi-4.5.22.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-build-4lb9c3ll/mod-wsgi/setup.py", line 301, in <module>
        INCLUDEDIR = get_apxs_config('INCLUDEDIR')
      File "/tmp/pip-build-4lb9c3ll/mod-wsgi/setup.py", line 273, in get_apxs_config
        stdout=subprocess.PIPE, stderr=subprocess.PIPE)
      File "/usr/lib64/python3.6/subprocess.py", line 707, in __init__
        restore_signals, start_new_session)
      File "/usr/lib64/python3.6/subprocess.py", line 1333, in _execute_child
        raise child_exception_type(errno_num, err_msg)
    FileNotFoundError: [Errno 2] No such file or directory: 'apxs'

apxs = Apache extension tool

ググってみたら、apxs は「APache eXtenSion tool」のことだそうで、apache-dev に含まれるそうな。早速、以下のコマンドで apache-dev をインストール。しかし、省略難しすぎ。

sudo yum install httpd-devel

これで大丈夫!と思ったけど、次は、gcc が入っていなくて怒られました。仕方ないので、gcc を yum 経由でインストール。

sudo yum install gcc
sudo /usr/local/bin/pip3 install mod_wsgi

デプロイ

必要なものは揃った!ってことで、Apache の設定とサンプル用のサイトを作ってみる。

サイトの作成

Hello Flask!をそのまま流用させていただく。

/var/www/flask/app.py
# coding: utf-8
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello, Flask!"

if __name__ == "__main__":
    app.run()

swgi ファイル

Apache というか、mod_swgiに読み込ませるファイルを作成

/var/www/flask/adapter.wsgi
# coding: utf-8
import sys
sys.path.insert(0, '/var/www/flask')

from app import app as application

Apacheの設定

Apache の conf.d に設定ファイルを追加し、app.py と adapter.wsgi が有効になるように設定。

/etc/httpd/conf.d/flask.conf
# /etc/httpd/modules には配置されないので指定が必要
LoadModule wsgi_module /usr/local/lib64/python3.6/site-packages/mod_wsgi/server/mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so

<VirtualHost *:80>
  ServerName ec2-xxxxxxx.amazonaws.com:80
  DocumentRoot /var/www/flask
  WSGIScriptAlias / /var/www/flask/adapter.wsgi
  <Directory "/var/www/flask/">
    options Indexes FollowSymLinks +ExecCGI
  </Directory>
</VirtualHost>

まとめ

python3、pip 辺りは他にも利用するだろうから、すでにインストールされている場合が多そう。なので、実質面倒なのは Apache(mod_wsgi)の設定周りかな。パッケージ化が進んでいると思っていたし、yum / pip といった便利なものがあるにも関わらず、gccが必要になるとは思わなかった。

次は、flask + DataBase + Template Engine ってとこかな。

続きを読む

クラウドベンダーの比較

はじめに

3大クラウドと呼ばれているAWS、GCP,Azureのリソースを比べてみました。
2017年11月時点の比較となります。

インフラ・サービスレベル

比較項目 AWS GCP Azure 備考
データセンター 各地で借りている すべて自前 各地で借りている(一部自前)
仮想化技術 Xen KVM Hyper-V
リージョン(国内) 1個所 1個所 2個所
リージョン(全国) 15個所 12個所 36個所
SLA 99.95 99.95 99.95 仮想サーバ

サービス面

比較項目 AWS GCP Azure 備考
仮想サーバ Amazon EC2 Google Compute Engine Azure Virtual Machines
仮想サーバ対応OS Amazon Linux,CentOS,RedHat,Windows Server,等 CentOS,RedHat,SLES,Windows Server,等 CentOS,RedHat,Windows Server,等
仮想サーバディスク SSD,HDD SSD,HDD SSD,HDD
仮想サーバスナップショット
仮想サーバオートスケール
コンテナ Amazon ECS Container Engine Container Service
RDB RDS Cloud SQL SQL Database
RDB冗長化
RDBリードレプリカ
RDB DB種別 Aurora,MySQL,MariaDB,Oracle,SQL Server,PostgreSQL MySQL,PostgreSQL SQL Server
NoSQL DynamoDB Cloud Datastore Cosmos DB
ビックデータ Redshift BigQuery App Service
メール Amazon SES
モニタリングツール CloudWatch Stackdriver Azure Monitor
ロードバランサー(L4) CLB Network load balancing Azure Load Barancer
ロードバランサー(L7) ALB HTTP load balancing Application Gateway
CDN Amazon CloudFront Google Cloud CDN Azure CDN
VPN Amazon VPC Google Cloud VPN VPN Gateway
DNS Route53 Google Cloud DNS Azure DNS
専用線 Direct connect Dedicated Interconnect Express Route

サポート面

比較項目 AWS GCP Azure 備考
ランク低 開発者 ($29/月 or 利用料の 3%/月) シルバー ($150/月) Standard($300/月)
ランク中 ビジネス($100/月 or 利用料 の10%/月) ゴールド($400/月) Professional Direct($1,000/月)
ランク高 エンタープライズ($15,000/月 or 利用料の10%) プラチナ(問合せ) Premier(問合せ)

費用面(リージョン日本)

比較項目 AWS GCP Azure 備考
課金単位
ディスカウント リザーブドインスタンス(前払い) 継続利用割引、利用確約の割引(前払い) エンタープライズ契約(前払い)
仮想サーバ(Type) t2.medium(2vCPU,4GB) n1-standard-2(2コア,7.5GB) A2 V2(2コア,4GB)
仮想サーバ(時) $0.0464(5.336円)※1 $0.0950(10.925円)※1 $0.15(17.25円)※1
仮想サーバ(月) $33.408(3841.92円)※1 $48.17(5539.55円)※1,※2 $108(12,420円)※1
インターネットへの転送量 $0.140/GB(10TBまで) $0.12/GB(1TBまで) $0.138/GB(5GB-10TB、5GBまでは無料)
ストレージ利用料 $0.025/GB (最初の50TB/月まで) ※S3 $0.016/GB 月 ※Regional Storage $0.2/GB(最初の50TB/月まで) ※BLOG Storage

※1 $1=115円換算
※2 継続利用割引含む

総括

 AWS、GCP,Azureでのサービス面では同じようなサービスを展開していることが判明。
 インフラ・サービスレベルでは、Azureがリージョン36個とTOPに。
世界的に見て幅を利かせているように思えた。
ただ、GCPはすべて自前のセンターでクラウドサービスを展開していることから、
新しいことをやるにも制約が低いように思えた。
私のイメージ的に一番シェアが高いAWSは、インフラ面ではGCP,Azureに劣っている結果となった。
 費用面では、Azureは割高。AWSが思ったよりも頑張っているように思えた。
 イメージ的にGCPは費用は安いと思っていたが、仮想サーバ比較だと、継続利用割引を使用してもAWSのほうが安い結果となった。
 ただ、費用に関しては、日々値下げ合戦が繰り広げられているので、今後のベンダーさんの努力に期待です。

最後に、費用面での算出に使用した見積もりツールです。
【AWS】http://calculator.s3.amazonaws.com/index.html
【GCP】https://cloud.google.com/products/calculator/?hl=ja
【Azure】https://azure.microsoft.com/ja-jp/pricing/calculator

続きを読む

VPC内に置いたElasticsearch ServiceにEC2のプロキシ経由でアクセスする

先日のアップデートでElasticsearch ServiceをVPC内で使えるようになりました。
https://aws.amazon.com/jp/blogs/news/amazon-elasticsearch-service-now-supports-vpc/

これまではパブリックなエンドポイントしか使えず、VPC内からアクセスするにはパブリックサブネットからの通信が必要でした。
VPC内に配置できれば、通信も全部VPC内で完結しますし、よりセキュアに使うことができるようになりますね。

さて、VPC内に配置したときに起きる問題の一つが、 直接ローカルからKibanaを見ることができない という問題です。
パブリックサブネットに配置してセキュリティグループで接続許可すれば行けるだろう、と最初は思ったんですが、どうやら無理みたいです。
※うまく行った、という方がいたらご教示ください…。

これを解決するためにどうするかについてはいろいろ調べてみました。
1. ALBを使う。
こちらを参考
https://dev.classmethod.jp/cloud/aws/make-public-kibana-amazon-es/
メリットは管理するサーバが増えないこと。
デメリットは、Elasticsearch ServiceのプライベートIPは可変なのに対し、ALBはターゲットにIPかEC2インスタンスしか設定できず、ターゲットのIPを定期更新するなどしなければならないこと。
1. EC2にKibanaをインストールして、Easticsearch Serviceを参照するようにする。
こちらを参考
https://dev.classmethod.jp/cloud/aws/make-public-kibana-amazon-es2/

メリットは、ドメイン指定が可能なのでElasticsearch ServiceのIPが変わっても大丈夫なことなど。 デメリットは、Kibanaの部分がEC2依存になること。
1. Windowsのインスタンスを立ててそこにリモートデスクトップでアクセスし、Windowsインスタンス内のブラウザからKibanaにアクセスする。
読んで字のごとくです。
メリットはやることが単純明快なことかな?
デメリットは大抵のケースで余計なEC2インスタンスを増やさざるを得ないこと。
1. EC2をプロキシサーバにする。(今回の方法)
EC2にKibanaを入れるパターンに近いですが、KibanaもElasticsearch Serviceのものを使用するので、Kibanaの可用性をElasticsearch Service(つまりAmazon側)に依存させたままにできるのがメリットです。
デメリットはこちらもアクセスがEC2依存になること。

今回は調べてもVPC内に配置したElasticsearch Serviceを参照するために使用したという例が見つからなかった、プロキシサーバを使う例について書いてみます。
※別の目的でプロキシサーバ経由にする例はたくさんありましたが、いずれも今回のアップデート以前の情報でした。
今回の例ではnginxを使用しますが、別にApacheでもなんでもいいと思います。

方法

パブリックサブネットにEC2インスタンスを用意する。

特に何も考えずにAmazon Linuxでよいと思います。
インスタンスタイプはとりあえずt2.microでもいいですが、
使ってるうちに負荷がしんどいなと思ったら適宜変更しましょう。
当然のことながら、SSHに加えhttpでアクセスできるようにセキュリティグループを設定します。
場合によっては踏み台サーバと共用とかでも大丈夫かなと。
※今回の例ではhttpを使用し、httpsではやらないようにします。
httpsを使用する例はこちら。(今回の設定もこちらを参考にしています。)
http://inokara.hateblo.jp/entry/2016/10/22/123538

用意したEC2からElasticsearch Serviceクラスタにアクセスできるようにする。

セキュリティグループの設定およびアクセスポリシーを適切に設定します。
セキュリティグループだけにしてもいいですし、リソースベース、IPベース、IAMユーザ・ロールベース等ポリシー設定できるのでその時の要件に沿って適切に設定すればOK。
http://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/es-createupdatedomains.html#es-createdomain-configure-access-policies
余談ですが、Elasticserch Serviceの設定変更には意外と時間がかかるので、なるべく設定変更が少ないほうが気持ちが楽だと思います。

EC2インスタンスにnginxをインストールする。

深く考えずにyumでOKです。

sudo yum -y install nginx

/etc/nginx/nginx.confを編集する。

50行目付近に

nginx.confの一部
        include /etc/nginx/default.d/*.conf;
        location / {
        }

みたいに空で設定されているところがあるので、下記のようにします。
※抜粋、略記しています。

nginx.confの一部
        include /etc/nginx/default.d/*.conf;
        location / {
            proxy_pass https://xxxxxxxxxxxxxx.amazonaws.com/;
        }

といった感じに、proxy_pathでVPCエンドポイントを指定します。
httpsじゃなくてもいいみたいですが、httpsで問題なくアクセスできます。

nginxを起動する。

nginxのサービスを起動します。ついでに自動起動もONにしておきましょう。

sudo service nginx start
sudo chkconfig nginx on

これで
http://{{設定したインスタンスのパブリックIP}}/_plugin/kibana
にアクセスしてやれば、EC2を経由して該当のElasticsearch ClusterのKibanaにアクセスできます。

課題とかおまけとか

後ろに_plugin/kibanaをつけないでアクセスするとElasticsearchにもアクセスできちゃうので、それを良しとするかどうかは要検討です。
逆にローカルから手軽にデータ投入できたりもするわけですが…。どこまで許容するかですね。
そこを気にするのであれば、nginxの設定とかでディレクトリごとにアクセス制御するとかが必要かもしれません。

あと、Elasticsearch Serviceを配置したVPCにVPN接続している場合はこんなことしなくてもVPNエンドポイントを指定して直接参照できる気がするので、試した方いたらご教示くださると嬉しいです。

ALBでElasticsearch Serviceのインスタンスを指定できるようになればいいんですけどねえ。

続きを読む

docker-lambdaでAWS Lambda環境をお手軽に動かす

Lambdaを使ってみて

お疲れ様です。本記事は、AWS Lambda Advent Calendar 2017の3日目の記事になります。

さて、Lambdaをがっつり本番環境で動かしていますという話もチラホラ聞きますが、私はLambdaを使い始めて約1年半、まだいまひとつガッツリ本番な気分になっていません。

その理由の一つがローカル開発環境問題です。ありきたり!
少し複雑なコードを書くとなると、デバッグしながらになるのでローカルマシンの使い慣れたエディタでやりたいところ。
ではささっと環境構築してみましょう。

ローカル開発環境の整備

その :one: 各言語のSDKをインストール

Lambdaで使える言語は今のところnode.js, Python, C#, Java(今後Golang, .NET)がありますが、MacでLambdaの開発環境を構築するとなると、

  • nodejs用

    $ npm -g install aws-sdk
    
  • Python用

    $ pip install python-lambda-local
    
  • Java用
    AWS Toolkitをインストール

以下略

当然全言語を使うわけではないですが、用途によって適正言語を使おうとすると、それぞれランタイムが必要。これらを今後バージョン管理していくとなると、若干見通しが暗く。。

その :two: 必要なライブラリのインストール

さらに、モジュールをImportしたりすると、それらもそれぞれbuild && デプロイパッケージ(要はZIPで固めて)をLambdaにアップロードするという二手間作業の発生

その :three: invalid ELF header対策

Lambdaは実際にはEC2のAmazon Linuxを立ち上げて動くことになるので、macOS上でビルドされたライブラリでは動かないケースが有る。いわゆる invalid ELF header 問題である。
じゃあちょろっとEC2インスタンス立ち上げて、ビルドしてパッケージングすれば解決。

もうローカル環境じゃなくなっちゃった!

2016年まではこのツラみがありましたが、今はもうAmazon Linux Dockerイメージが出た!
これでEC2インスタンスを立ち上げるのはなんとか回避できるようになりました。

その :four: 実行&デプロイ(ざっくり)

  • nodejs用
    メイン処理を実行するファイル lambda_handler.jsを作る(ファイル名は任意で)

    $ node lambda_handler.js
    

    実装が完了したら、それらを固めてデプロイするためのgulp.taskを作る

  • Python用
    メイン処理を実行するファイル lambda_handler.pyを作る(ファイル名は任意で)

    $ python-lambda-local -l lib/ -f handler -t 30 lambda_handler.py event.json
    

以下略再び

というか、 サーバのプロビジョニングの必要がないのがLambdaの売りなので、 もうだいぶ前の時点で既に本末転倒なんじゃないか感があったのに気づかないふりをしていた自分。。

もっとこうスマートに何か!

こういった状況の一つのソリューションとしてServerless Frameworkがあります。

こちらメリットとしては、

  • slsコマンドでビルドやデプロイなど大抵のことが一発完了
  • 設定もymlでパッケージ管理しやすい

という点がありますが、一方で

  • npmインストールして使う以上、結局管理対象が増えるのでは?
  • AWSの管理者権限が付与されたIAMロールが必要
    (なので、所属組織によっては開発者全員が使うのは難しいかも)
  • 上述のネイティブライブラリ問題は据え置き

といった点が個人的には引っかかりました。

ここまでで既に勘の良い人はお気づきかと思いますが

Dockerで管理する

「これDockerで全部やれるんじゃないか?」

先程このへんで触れたAmazon Linux Docker Image、これに諸々入れる分にはローカルのマシンを基本汚さずに済む。
そして、開発が終わったらコンテナごと廃棄ドボンしてスッキリ。

あとはまた、Lambdaでの開発が必要なときにそのつど docker buildするわけですが、うまいことDockerfileが保守されていれば理想的ですよね。

何より普段Dockerでアプリケーション開発してるんなら、Dockerでまとめてしまうのが見通しがよい。

そんなLambda用のDockerイメージを作れば良い

と思いましたが、lambci/docker-lambdaというLambda用Dockerイメージがありました。

Screen Shot 2017-12-04 at 2.50.05.png
https://speakerdeck.com/hihats/aws-lambdafalsejin-xian-zai?slide=18

LambciというOSSプロジェクトなので、自作より皆で保守していったほうが間違いない。
活発にアップデートされているので、Goへの対応なども楽しみです。

さっそく使ってみる

lambci/lambda:python3.6 イメージをベースにして実行

print_json.py
# 引数で渡されたJSONをそのまま出力するだけのPythonスクリプト
import json

def lambda_handler(event, context):
    print(event)
sample.json
  {
    "type": "products",
    "id": 123,
    "attributes": {
      "name": "Fun Toy",
      "description": "Toy for infants",
      "state": "in sale",
      "slug": "4b5366e5",
      "photo": "TOY.jpg"
    }
  } 

以下のように、(拡張子なしファイル名):関数名 をコマンドとしてイメージに渡してdocker runしてあげるだけで、実行環境のbuild(イメージがなければpullも)から関数実行までやってくれます

$ docker run -v "$PWD":/var/task lambci/lambda:python3.6 print_json.lambda_handler $(printf '%s' $(cat sample.json))

Unable to find image 'lambci/lambda:python3.6' locally
python3.6: Pulling from lambci/lambda
5aed7bd8313c: Pull complete
d60049111ce7: Pull complete
216518d5352c: Pull complete
47aa6025d0bc: Pull complete
9a82bb1662ac: Pull complete
Digest: sha256:3663b89bd1f4c4d1a4f06a77fc543422c1f0cbfc3a2f491c8c7bdc98cf9cf0b6
Status: Downloaded newer image for lambci/lambda:python3.6
START RequestId: 6cf5f6b5-bf62-49de-aaa4-f05b1148b67e Version: $LATEST
{'type': 'products', 'id': 123, 'attributes': {'name': 'FunToy', 'description': 'Toyforinfants', 'state': 'insale', 'slug': '4b5366e5', 'photo': 'TOY.jpg'}}
END RequestId: 6cf5f6b5-bf62-49de-aaa4-f05b1148b67e
REPORT RequestId: 6cf5f6b5-bf62-49de-aaa4-f05b1148b67e Duration: 109 ms Billed Duration: 200 ms Memory Size: 1536 MB Max Memory Used: 19 MB 

実行ファイルとコマンドワンライナーでいけました :exclamation::sushi:

build用イメージ lambci/lambda:build-python3.6 をベースにして環境をbuild

Lambdaがデフォルトで扱ってくれないライブラリが必要な処理のケースでは、ビルド & デプロイパッケージングするためのイメージ(lambci/lambda:build-python3.6)をベースにDockerfileでゴニョゴニョする

FROM lambci/lambda:build-python3.6
ENV LANG C.UTF-8
ENV AWS_DEFAULT_REGION ap-northeast-1

WORKDIR /var/task
ADD . .

RUN /bin/cp -f /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
  pip install -r requirements.txt -t /var/task

CMD zip -9 deploy_package.zip search.py && \
  zip -r9 deploy_package.zip *

必要なモジュールはrequirements.txtに羅列

requirements.txt
twitter
pymongo
numpy
requests_oauthlib
pytz

ビルドしてみる

$ docker build -t twitter_search .

Sending build context to Docker daemon  107.5MB
Step 1/7 : FROM lambci/lambda:build-python3.6
 ---> a895020ff4f5

<中略>

Successfully installed certifi-2017.11.5 chardet-3.0.4 idna-2.6 numpy-1.13.3 oauthlib-2.0.6 pymongo-3.5.1 pytz-2017.3 requests-2.18.4 requests-oauthlib-0.8.0 twitter-1.18.0 urllib3-1.22  

必要なモジュールがdockerに入っていき、実行環境が整いました。

既に上のDockerfileのCMD文にsearch.pyとファイル名が書かれていますが、今回は 「Twitterで特定のキーワード検索した結果をmongodb(ローカルのDockerコンテナ)にINSERTする」 Lambda関数を用意。

search.py
import os
from twitter import *
from requests_oauthlib import OAuth1Session
from requests.exceptions import ConnectionError, ReadTimeout, SSLError
import json, datetime, time, pytz, re, sys,traceback, pymongo, pprint
from pymongo import MongoClient
from collections import defaultdict
import numpy as np
import csv

def lambda_handler(event, context):
    pp = pprint.PrettyPrinter(indent=4)
    mongo_host = os.environ['MONGODB_HOST']
    secrets = {
        'consumer_key': event['CONSUMER_KEY'],
        'consumer_secret': event['CONSUMER_SECRET'],
        'access_token': event['ACCESS_TOKEN'],
        'access_token_secret': event['ACCESS_SECRET']
    }
    s_pa = [
        secrets["access_token"],
        secrets["access_token_secret"],
        secrets["consumer_key"],
        secrets["consumer_secret"]
    ]
    query = event["KEYWORD"]

    t = Twitter(auth=OAuth(s_pa[0], s_pa[1], s_pa[2], s_pa[3]))

    client = MongoClient(mongo_host, 27017)
    db = client.twitter_db
    tw_collection = db.tweets
    metadata_collection = db.metadata

    while(True):
        results = t.search.tweets(q=query, lang='ja', result_type='recent', count=100, max_id=0)
        metadata_collection.insert(results['search_metadata'])
        if len(results['statuses']) == 0:
            sys.stdout.write("statuses is none. ")
            break
        for tw in results['statuses']:
            if tw_collection.find_one({'id': tw['id']}) is None:
                tw_collection.insert(tw)

        print(len(results['statuses']))
        if not 'next_results' in results['search_metadata']:
            sys.stdout.write("no more results. ")
            break
        since_id = results['search_metadata']['since_id']

secret.jsonにTwitterAPIのKEYやらmongoのホストアドレスやら検索したいクエリやらをぶちこみ :arrow_down: 実行する

$ docker run -v "$PWD":/var/task lambci/lambda:python3.6 search.lambda_handler $(printf '%s' $(cat secret.json))

START RequestId: afc3baf7-09d1-4407-85b7-e012e759053b Version: $LATEST
30 recorded
no more results. END RequestId: afc3baf7-09d1-4407-85b7-e012e759053b
REPORT RequestId: afc3baf7-09d1-4407-85b7-e012e759053b Duration: 2070 ms Billed Duration: 2100 ms Memory Size: 1536 MB Max Memory Used: 38 MB

とれました :exclamation::sushi::sushi:

注意するのは、ビルド用と関数実行用のイメージは別(`lambci/lambda:build-python3.6`はあくまでビルド&パッケージングだけで使う)ということ

無事実装が終わればパッケージング

$ docker run -v "$PWD":/var/task --name twitter_search twitter_search:latest
$ ls deploy_package.zip
deploy_package.zip

deploy_package.zipができていることが確認できました。

結論

Docker最高ですね。

LambdaのAdvent calendarなのにDockerアゲになってしまいました :bow:

参考記事

Serverless Frameworkのプラグインを利用した外部モジュールの管理
AWS Lambda 用の python パッケージをクロスコンパイルして serverless で deploy した話

続きを読む

EC2がプライベートサブネットでも利用しやすくなりました! #reinvent

しかし、もはや時刻同期がAWS内部で完結できるようになりました。 改めて言えば、先日AWS PrivateLinkも発表されており、まだ一部のサービスのみですがAWS APIへのアクセスもプライベートで実行できるようになっています。 さらに、Amazon Linuxに関しては、以前記事にしましたが、S3エンドポイントを利用すればyumの … 続きを読む