読者です 読者をやめる 読者になる 読者になる

はてダ

はてブロなのにはてダ!!!!!

直積を実装する

Python 計算機科学

Python には、 itertools パッケージに product() があるわけですが、 今回はこれを自分で実装してみます。

2 変数の直積

2 変数の直積については、特に難しく考えず、愚直に実装します。

def product(xs, ys):
    return (x + y for x in xs for y in ys)

assert list(product('ab', 'cd')) == ['ac', 'ad', 'bc', 'bd']

3 変数以上の直積

3 変数以上の直積になると、よくわからなくなるので定義を確認します。

Wikipedia によると、 直積集合は結合法則が成り立つと 見なして よいとされています。

結合法則が成り立つということは、元となる集合を 2 つずつ再帰的に関数を適用することで 3 変数以上の直積を取り出すことができるはずです。

2 変数版の関数を用いて試してみます。

assert list(product(product('ab', 'cd'), 'ef')) == ['ace', 'acf', 'ade', 'adf', 'bce', 'bcf', 'bde', 'bdf']

したがって、3 変数以上の直積集合を得るための関数は、次の通り実装できます。

def product(*args):
    xs, ys, args = args[0], args[1], args[2:]
    if len(args) > 0:
        return (z for z in product(product(xs, ys), *args))
    else:
        return (x + y for x in xs for y in ys)

ただ、この実装は少々冗長です。 product(product(product(... と関数を適用していくわけですから、これは畳みこみを使えばよいはずです。

実際に試してみます。

from functools import reduce

def product(xs, ys):
    return (x + y for x in xs for y in ys)

assert list(reduce(product, ['ab', 'cd', 'ef'])) == ['ace', 'acf', 'ade', 'adf', 'bce', 'bcf', 'bde', 'bdf']

reduce() を使っても期待通りの結果を得ることできました。

from functools import reduce

 def product(*args):
     return reduce(
         lambda xs, ys: (x + y for x in xs for y in ys),
         args
     )

assert list(reduce(product, ['ab', 'cd', 'ef'])) == ['ace', 'acf', 'ade', 'adf', 'bce', 'bcf', 'bde', 'bdf']

というわけで、 reduce() を使うと非常にシンプルな実装で直積を実装することがわかりました。

最近の悩みは、もっぱら、この手のあんまり生産性にもお金にも寄与しないことばっか楽しくなって、石油王への道が遠のいていることです。

今年おいしかったリンゴメモ

果実 無題

今年はいろいろな品種のりんごを食べたので、メモ。

シナノスイート

長野県産。出荷時期は 10 月から 11 月にかけて。 1 玉 100 円前後で、手ごろながら甘くておいしい。

今年一番おいしかった品種かもしれない

シナノスイート|品種紹介|りんご情報局

シナノゴールド

長野県産。出荷時期は 11 月ごろ。 黄色いリンゴで、シナノゴールドと兄弟品種らしい。

シナノゴールドと同じく甘くておいしい。リンゴらしいリンゴの味わい

シナノゴールドに比べて流通量が少ないのか、 1 度か 2 度くらいしか購入できなかった。

シナノゴールド|品種紹介|りんご情報局

あいかの香り

長野県産。出荷時期は 12 月中旬以降の模様。 訳あり品なら 1 玉 100 円程度で買える。

蜜がたっぷりでおいしい。

あいかの香り

名月

長野県産。正式には「ぐんま名月」というらしい。 店頭に出回ったのは 12 月中旬以降だった。

あいかの香りと同様、訳あり品で 100 円程度。

甘くておいしい。蜜もたっぷり。あいかの香りと近い。

ぐんま名月

Django の Form のバリデーションについて整理する

django Python

この記事は、 2015 tech-yuruyuru アドベントカレンダー 5 日目の記事です。

Django の Form には、色々なバリデーションの種類が存在します。

色々な種類に分かれている以上、それぞれに役割が存在しますし、 適切な場所にバリデーションを書かないと、そもそも呼び出してもらえなかったりします。

呼び出し階層

Django 1.8 における Form のバリデーションは、 次のような呼び出し階層になっています

  1. forms.forms.BaseForm.is_valid:: self -> bool
    1. forms.forms.BaseForm.errors:: self -> ErrorDict
      1. forms.forms.BaseForm.full_clean:: self -> void
        1. forms.forms.BaseForm._clean_fields:: self -> void

          • すべてのフィールドについて、バリデーションを実行する
          • バリデータが ValidationError を投げた場合、 except して self.add_error(<fieldname>, ValidationError) する

          • raises ValidationError forms.fields.Field.clean:: str -> a

            1. raises ValidationError forms.fields.Field.to_python:: str -> a

              • Python のデータ型 a に変換できれば、変換した値を返す
              • 変換できなければ ValidationError を投げる
            2. raises ValidationError forms.fields.Field.validate:: a -> void

              • to_python:: str -> a で変換された a 型を受け取る
              • Field でのバリデーションを行う
              • バリデーションエラーがあれば、 ValidationError を投げる
            3. raises ValidationError forms.fields.Field.run_validators:: a -> void

              • self.validators ([a -> void]) を全て実行する
              • self.validators 内のいくつかのバリデータが ValidationError を投げた場合、 ひとつの ValidationError にまとめて投げ直す

              • raises ValidationError a -> void

          • raise ValidationError clean_<fieldname>:: self -> a

            • BaseForm のサブクラスが clean_<fieldname> というメソッドを 実装していた場合、実行される
        2. forms.forms.BaseForm._clean_form:: self -> void

          1. raises ValidationError forms.forms.BaseForm.clean:: self -> cleaned_data
            • 複数フィールドにまたがって行う必要があるバリデーションを実装する
            • 返り値が None なければ self.cleaned_data に設定される
            • フィールドのバリデーションで発生したエラーは、 self.errors から取得できる
        3. forms.forms.BaseForm._post_clean:: self -> void

変な表記の仕方のをしてしまいましたが

  • raises <ExceptionType> <Function-or-Method> は、 <Function-or-Method><ExceptionType> を raise するかも
  • <Function-or-Method>:: a -> b は、 型アノテーションみたいなやつ

という意味です

バリデーションの流れ

  1. フィールドのバリデーション
  2. フォームのバリデーション

という順序でバリデーションが実行されます。

class SomeForm(Form):
    # ...
    def clean_somefield(self):
        # フィールドごとのバリデーション

    def clean(self):
        # フィールドをまたいだバリデーション

フィールドのバリデーション

フィールのバリデーション大まかに、

  1. Field のバリデーション
  2. Form の clean_<fieldname>()

の 2 つがあります。

clean_<fieldname>() は、 Field を実装する必要がなく実装が楽ではありますが、 Field のバリデーションに失敗すると実行されないことに注意してください。

validators

Field には、 validators という便利な機能があります。

Field のコンストラクタに、バリデーション関数のコレクションを渡すだけで、 フィールドのバリデーションを設定できます。

def validate_today(value, today=None):
    if today is None:
        today = datetime.date.now()

    if value != today:
        raise ValidationError("Not today")


class SomeForm(Form):
    a_field = DateField(validators=[validate_today])

このバリデーション関数は、 フィールドの値を受け取り値の妥当性を検証し、 問題があれば ValidationError を raise するというシンプルな実装で済みます。

バリデータの再利用が可能というメリットはもちろんですが、 ただの関数であるため、 Form のインスタンスを生成せずにバリデータのテストが書ける というメリットもあります。

一方で、 Form の状態に依存するバリデーションを実装することはできませんし、 Field.clean() でバリデーションに失敗するとやはり validators は呼び出されない ので注意が必要です

フォームのバリデーション

フォームのバリデーションには、 フィールドをまたぐようなバリデーション処理を実装します

どこにバリデーションを書くか

例えば、以下のような指針が考えられます

  • Form の状態に依存しないフィールドのバリデーション: Field.validators
  • Form の状態に依存するフィールドのバリデーション: Form.clean_<fieldname>()
  • フィールドをまたいだバリデーション: Form.clean()

絶対ではありませんし、もちろんプロジェクトのアーキテクチャが優先にはなりますが、 それぞれのバリデータがどういった目的で存在するのかを整理しておくと、 Form や Field のバリデーションを実装するときに迷わずに済むのではないでしょうか。

Windows 10 にアップデートしたので、開発環境を再構築しました

Docker Windows MSYS2

この記事は、 2015 tech-yuruyuru アドベントカレンダー 4 日目の記事です。

VL ゴシックのインストール

フォントは、もうずっと VL ゴシックを使っています。

最低限 1Il|0O の見分けがきちんとつくフォントであれば十分なので、 こだわりとかはあんまりないです。

MSYS2 の導入

ここ 3 年ほどは Cygwin を使っていたのですが、 最近は MSYS2 が良いと聞くので、 MSYS2 に移行しました。

ConEmu の導入

ConEmu

ここ 3 年ほどは Cygwin + mintty を使っていたものの、 後述する Dokcer の問題で mintty から ConEmu に移行しました。

上記公式サイトからダウンロードしたところ、 MSYS2 の設定も入っていたので、 ConEmu 側は、フォントの設定以外は特に変更せずに使えています。

一方で Bash 側は多少対応が必要で、 clear コマンドが動かないので、 Clear console buffer in ConEmu with Cygwin を参考に、 下記のエイリアスを設定しました。

alias clear="echo -e '\0033\0143'"

Docker Toolbox のインストール

Install Docker for Windows

Docker Toolbox をインストールしました。

Docker Toolbox でインストールされる Bash ではなく、 普段使う MSYS2 の Bash から Docker を使いたいので、 MSYS2 の .bash_profile に以下の設定しました。

# Docker
pushd '/c/Program Files/Docker Toolbox'
DOCKER_MACHINE=./docker-machine.exe
VM=default
if [ "$($DOCKER_MACHINE status $VM)" != "Running" ]; then
  echo "Starting machine $VM..."
  $DOCKER_MACHINE start $VM
  yes | $DOCKER_MACHINE regenerate-certs $VM
fi
echo "Setting environment variables for machine $VM..."
eval "$($DOCKER_MACHINE env --shell=bash $VM)"
popd

これで、 docker コマンドが利用できるようになりました。

mintty でのエラー

mintty は tty を持たないので、 docker run -it コマンドが "cannot enable tty mode on non tty input" というエラーを吐きます。

今回は、 ConEmu を使うことで、この問題を回避しています。

また、 Github にも Issue が 上がっていますが、今のところ修正される目途はたっていないようです。

Ansible の Inventory file についておさらい

Ansible インフラ

この記事は、 2015 tech-yuruyuru アドベントカレンダー 3 日目の記事です。

Inventory file とは何か

Ansible は、インフラ内の複数システムに対して同時に動作します。 Inventory file は、 Ansible が動作する対象のシステムを列挙するためのファイルです。

Host と Group

では、実際に Inventory file を見ていきます

まず、動作対象となる以下のシステムを Vagarant で立ち上げます

  • mail: メールサーバ
  • web1, web2: Web サーバ
  • db1, db2: DB サーバ
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "debian-8.2"
  config.vm.network "private_network", type: "dhcp"
  # 動作の確認が目的なので SSH 秘密鍵を INSECURE なままにしておく
  config.ssh.insert_key = false

  [:mail, :web1, :web2, :db1, :db2].each do |name|
    config.vm.define name do |server|
      server.vm.hostname = name
      # mDNS を使うため Avahi をインストールする
      server.vm.provision "shell", inline: <<-SHELL
        sudo apt-get update && sudo apt-get upgrade -y
        sudo apt-get install -y avahi-daemon
      SHELL
    end
  end
end
$ vagrant up
Bringing machine 'mail' up with 'virtualbox' provider...
Bringing machine 'web1' up with 'virtualbox' provider...
Bringing machine 'web2' up with 'virtualbox' provider...
Bringing machine 'db1' up with 'virtualbox' provider...
Bringing machine 'db2' up with 'virtualbox' provider...
... 後略
$

次に inventory というファイル名で、 Inventory file を作成します

# ./inventory
mail.local

[webservers]
web1.local
web2.local

[dbservers]
db1.local
db2.local

mail.local, web1.local といったように、 動作対象となる Host を列挙します

[webservers] のようにブラケット ([]) で囲まれた名前は、 Group の名前です。 Group は、目的や操作のタイミングなどで Host をグルーピングするために使います

一度、 Ansible でこの Inventory file を使って ping を打ってみます

$ # すべての Host に ping
$ # ansible [host] -u [user] --private-key=[/path/to/private_key] -m ping -i [/path/to/inventory_file]
$ ansible '*'  -u 'vagrant' --private-key='~/.vagrant.d/insecure_private_key' -m ping -i ./inventory
web1.local | success >> {
    "changed": false, 
    "ping": "pong"
}

mail.local | success >> {
    "changed": false, 
    "ping": "pong"
}

db2.local | success >> {
    "changed": false, 
    "ping": "pong"
}

web2.local | success >> {
    "changed": false, 
    "ping": "pong"
}

db1.local | success >> {
    "changed": false, 
    "ping": "pong"
}

$ # Host を指定して ping
$ ansible web1.local  -u 'vagrant' --private-key='~/.vagrant.d/insecure_private_key' -m ping -i ./inventory 
web1.local | success >> {
    "changed": false, 
    "ping": "pong"
}

$ # Group を指定して ping
$ ansible dbservers  -u 'vagrant' --private-key='~/.vagrant.d/insecure_private_key' -m ping -i ./inventory 
db1.local | success >> {
    "changed": false, 
    "ping": "pong"
}

db2.local | success >> {
    "changed": false, 
    "ping": "pong"
}

無事、 ping が打てました

Host Variable

注意:

Host Variable/Group Variable を Inventory ファイル書くことは、 推奨されていません Splitting Out Host and Group Specific Data

Host の変数を Inventory file 内で定義することもできます

http_porthoge という Host Variable を web1, web2 に定義してみます

# ./inventory
[webservers]
web1.local http_port=80 hoge=fuga
web2.local http_port=80 hoge=piyo

Host Varible が定義されたこと Playbook を作成して確認してみます

# inventory-host_variable.yml
- hosts: webservers
  tasks:
  - debug: msg="http_port {{ http_port }}"
  - debug: msg="hoge {{ hoge }}"
$ # ansible-playbook -u[user] --private-key=[/path/to/private_key] -i [/path/to/inventory_file] [/path/to/playbook]
$ ansible-playbook -uvagrant --private-key=~/.vagrant.d/insecure_private_key -i inventory playbook-host_variable.yml

PLAY [webservers] ************************************************************* 

GATHERING FACTS *************************************************************** 
ok: [web1.local]
ok: [web2.local]

TASK: [debug msg="http_port {{ http_port }}"] ********************************* 
ok: [web1.local] => {
    "msg": "http_port 80"
}
ok: [web2.local] => {
    "msg": "http_port 80"
}

TASK: [debug msg="hoge {{ hoge }}"] ******************************************* 
ok: [web1.local] => {
    "msg": "hoge fuga"
}
ok: [web2.local] => {
    "msg": "hoge piyo"
}

PLAY RECAP ******************************************************************** 
web1.local                 : ok=3    changed=0    unreachable=0    failed=0   
web2.local                 : ok=3    changed=0    unreachable=0    failed=0

Host ごとに Host variable が定義されていることが確認できました

Group Variable

Host Variable と同様に、 Group の変数を Inventory file 内で定義することもできます

Group Variable は、 [group_name:vars] で定義します

# ./inventory
[webservers]
web1.local
web2.local

[webservers:vars]
http_port=80
time_zone=Tokyo/Asia

Group Varible が定義されたこと Playbook を作成して確認してみます

# inventory-host_variable.yml
- hosts: webservers
  tasks:
  - debug: msg="http_port {{ http_port }}"
  - debug: msg="time_zone {{ time_zone }}"
$ ansible-playbook -uvagrant --private-key=~/.vagrant.d/insecure_private_key -i inventory playbook-host_variable.yml 

PLAY [webservers] ************************************************************* 

GATHERING FACTS *************************************************************** 
ok: [web1.local]
ok: [web2.local]

TASK: [debug msg="http_port {{ http_port }}"] ********************************* 
ok: [web2.local] => {
    "msg": "http_port 80"
}
ok: [web1.local] => {
    "msg": "http_port 80"
}

TASK: [debug msg="time_zone {{ time_zone }}"] ********************************* 
ok: [web1.local] => {
    "msg": "time_zone Tokyo/Asia"
}
ok: [web2.local] => {
    "msg": "time_zone Tokyo/Asia"
}

PLAY RECAP ******************************************************************** 
web1.local                 : ok=3    changed=0    unreachable=0    failed=0   
web2.local                 : ok=3    changed=0    unreachable=0    failed=0 

Group 内の全ての Host に Group Variable が定義されたことがわかります

小グループ

Group の Group を作成することもできます

例として、 AWS で 2 つ Availability Zone に、 2 つずつ Web サーバをおいた場合を考えてみます

# ./inventory
# az-a に 2 台
[ap-norheast1a]
web[1:2].local

# az-c に 2 台
[ap-norheast1c]
web[3:4].local

[webservers:children]
ap-norheast1a
ap-norheast1c

# 親グループの Group Variable
[webservers:vars]
http_port=80

# 子グループの Group Variable
[ap-norheast1a:vars]
availability_zone=a

# 子グループの Group Variable
[ap-norheast1c:vars]
availability_zone=c
$ ansible-playbook -uvagrant --private-key=~/.vagrant.d/insecure_private_key -i inventory-group_of_group playbook-group_of_group.yml

PLAY [webservers] ************************************************************* 

GATHERING FACTS *************************************************************** 
ok: [web3.local]
ok: [web4.local]
ok: [web2.local]
ok: [web1.local]

TASK: [debug msg="http_port {{ http_port }}"] ********************************* 
ok: [web1.local] => {
    "msg": "http_port 80"
}
ok: [web3.local] => {
    "msg": "http_port 80"
}
ok: [web2.local] => {
    "msg": "http_port 80"
}
ok: [web4.local] => {
    "msg": "http_port 80"
}

TASK: [debug msg="availability_zone {{ availability_zone }}"] ***************** 
ok: [web1.local] => {
    "msg": "availability_zone a"
}
ok: [web2.local] => {
    "msg": "availability_zone a"
}
ok: [web3.local] => {
    "msg": "availability_zone c"
}
ok: [web4.local] => {
    "msg": "availability_zone c"
}

PLAY RECAP ******************************************************************** 
web1.local                 : ok=3    changed=0    unreachable=0    failed=0   
web2.local                 : ok=3    changed=0    unreachable=0    failed=0   
web3.local                 : ok=3    changed=0    unreachable=0    failed=0   
web4.local                 : ok=3    changed=0    unreachable=0    failed=0   

$ 

このように、

  • グループ内すべてで共通の Group Variable host_port が、 子グループ内の Host すべてで定義されていること
  • 子グループ内の Group Varialbe availability_zone が、 子グループごとに定義されている

ことがわかります

また、親グループと子グループで同じ名前の Group Variable が定義された場合、 子グループ側の Group Variable で上書きされるようです

[all:vars]

[all:vars] を用いると、すべてのホストに対して Group Variable を定義することができます

したがって、 SSH のユーザや秘密鍵のパスなどをまとめて定義できます

# ./inventory
# ...
[all:vars]
ansible_ssh_user=vagrant
ansible_ssh_private_key_file=~/.vagrant.d/insecure_private_key

これで、今まで以下のように、コマンドラインオプションで指定していた接続設定が

$ ansible-playbook -uvagrant --private-key=~/.vagrant.d/insecure_private_key -i inventory playbook.yml

以下のように省略できるようになります

$ ansible-playbook -i inventory playbook

便利な使い方

ポートの指定

host:port という形式でのポート指定

web1.local:22

ansible_port 変数を使ったポート指定

web1.local ansible_port=22

複数 Host のリスティング

[1:3][a:c] といった形式でまとめて Host を定義できます

web[1:2].local

ansible_ プレフィックスの Host Variable

ansible_port のように、 Ansible の挙動を制御するためのパラメータ (Host Variable) が いくつか存在しており、 List of Behavioral Inventory Parameters にリファレンスが掲載されています

参考資料

mDNS を使いローカルマシン内の仮想環境に接続する

Python インフラ

この記事は、 2015 tech-yuruyuru アドベントカレンダー 2 日目の記事です。

ローカルマシン内の仮想環境へアクセスするには、いくつかの方法があります。 この記事では、 mDNS を用いて名前解決行い、 仮想環境へのアクセスする方法について説明します。

mDNS とは何か

mDNS は、ローカルネットワーク内の機器を、 DNS サーバなどを介さずに自動的に 発見するための(サービスディスカバリ)仕組みです。

mDNS は、 Apple が策定したオープンな仕様で、 Apple 製の OS X はもちろん、 ソフトウェアをインストールすることで LinuxWindows でも利用可能です。

特定の DNS サーバを介すことはありませんが、 RFC 6752 に記載されている通り、 mDNS 自体は DNS に基づいた技術です。

ユニキャストである通常の DNSDNS サーバにクエリを投げるように、 マルチキャストアドレス 224.0.0.251 の UDP 5353 ポートに DNS クエリを投げると、対応する機器が応答します。

また、 mDNS では、 .local. という TLD を冠します。

dig

DNS にもとづいているため、 dig を使うことができます。

例えば my-machine というホスト名のマシンの IP アドレスを 見つけるには以下のようにします。

$ dig +short my-machine.local. @224.0.0.251 -p 5353
192.168.1.42

デモ

Vagrant を用いて、 Cent OS 6 と Debian 8 に avahi をインストールし、 getaddrinfo() で各仮想マシンに割り振られた IP アドレスを確認します

以下のの通り Avahi をインストールするだけの Vagrantfile を作成し、 vagrant up します

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|

  # DHCP で自動的に IP アドレスを割り当てる
  config.vm.network "private_network", type: "dhcp"

  config.vm.define :centos do |server|
    server.vm.box = "chef/centos-6.5"
    server.vm.hostname = :centos
    server.vm.provision "shell", inline: <<-SHELL
      sudo yum update -y
      sudo yum install -y http://ftp.jaist.ac.jp/pub/Linux/Fedora/epel/6/x86_64/nss-mdns-0.10-8.el6.x86_64.rpm
      sudo service messagebus start
      sudo service avahi-daemon start
    SHELL
  end

  config.vm.define :debian do |server|
    server.vm.box = "debian-8.2"
    server.vm.hostname = :debian
    server.vm.provision "shell", inline: <<-SHELL
      sudo apt-get update && apt-get upgrade -y
      sudo apt-get install -y avahi-daemon
    SHELL
  end
end

無事、 vagrant up に成功し、プロビジョニングまで終わったら、 各仮想マシンに割り当てたホスト名から、それぞれの IP アドレスを引いてみます。

今回は、 IP アドレスを引くために getaddrinfo() を用いてみます

$ python
>>> from socket import getaddrinfo
>>> { h: getaddrinfo(h + '.local', 0)[0][4][0] for h in ['debian', 'centos']}
{'debian': '172.28.128.4', 'centos': '172.28.128.3'}

仮想マシンに割り振られた、 IP アドレスを無事に引くことができました。

mDNS を使うことで、例えば /etc/hosts を毎回更新するといった手間から解放されます。

問題

ただし、 mDNS を使う場合、ローカルネットワーク内のマシンが信用できることが前提で、 偽名を名乗るマシンがネットワーク内に存在する場合には、問題が発生します。

マルチキャストパケットが、仮想環境のローカルネットワークだけに流れるように ルーティングすれば、もしかしたら、この問題は回避できるかもしれませんが、未確認です。

参考

AWS の「プライベートサブネット」とは何か

AWS ネットワーク

この記事は、 2015 tech-yuruyuru アドベントカレンダー 1 日目の記事です。

 AWSVPC には、「プライベートサブネット」を作成することができます。 ただし、 VPC のサブネットに、「プライベートサブネット」という種類のサブネットが存在するわけではあります。

 この記事では、まず「プライベートサブネット」とは何であるのかを確認します。 また、次回以降の記事で、サブネットが「プライベートサブネット」と「パブリックサブネット」のどちらであるのかの判別方法と、 「プライベートサブネット」の作成方法を説明します。

「プライベートサブネット」とは何か

 「プライベートサブネット」とは、インターネットへの「ルート」がない「サブネット」のことです。 プライベートサブネットからインターネットへのトラフィックは、 「パブリックサブネット」に配置された「 NAT インスタンス」を経由します。

 もう少し詳しく見てみます。各 VPC には、「サブネット」と「ルートテーブル」が存在します。  サブネットは、 EC2 インスタンスや RDS インスタンスといった、 「 AWS のリソース」を配置するための IP アドレスの範囲です。 ルートテーブルは、サブネットのネットワークトラフィックの経路を制御する一連のルールです。

 サブネットに配置されたリソースがインターネットに接続するには、 まず、 VPC へ「インターネットゲートウェイ (IGW) 」を追加する必要があります。 VPC 内のリソースは、基本的に IGW を経由してインターネットと通信するためです。 次に、サブネットのトラフィックが IGW へ流れるように「ルーティング」する必要があります。 この設定を行うのが「ルートテーブル」です。

名前 概要
サブネット AWS リソースを配置するための IP アドレスの範囲
ルートテーブル サブネットのトラフィックの経路を制御する一連のルール
インターネットゲートウェイ (IGW) VPC 内のリソースと インターネットとの通信に使われるコンポーネント

 IGW へトラフィックが流れるようにルートテーブルが設定されたサブネットを「パブリックサブネット」と呼びます。 パブリックサブネットに配置されたリソースからのトラフィックは IGW へ流れるようにルーティングされているので、 パブリックサブネット内のリソースはインターネットと直接通信することできます。

 では、プライベートサブネットとは何なのでしょうか。 繰り返しになりますが、プライベートサブネットは、インターネットへのルートがないサブネットのことです。 言い換えると、「プライベートサブネット」というのは、 サブネット内のリソースからのトラフィックが IGW へ流れるようにルーティングされていないサブネットということになります。

 したがって、サブネットが「プライベートサブネット」であるか「パブリックサブネット」であるかは、 「ルートテーブル」の設定次第であるということです。

 次回以降、プライベートサブネットの判別方法や作成方法について詳しく追っていきます。