SSHポートフォワードを利用してGPUサーバを使う

機械学習に使うGPUサーバをAWS上のPrivateSubnetに置いているので、直接JupyterNotebookやTensorBoardを使う事はできません。
そこでSSHトンネルを作って外から接続できないGPUサーバへ踏み台サーバを経由して接続できるようにします。

ローカルフォワード

ローカルフォワードは良く使われる方法で、通信を踏み台サーバ(ここではBastianサーバ)から別の宛先に転送する

設定

  • 源ポート:19999(localhostで使用するポートを記載)
    ※空いているポートであれば何でもOK
  • 送り先:10.0.0.24:19999(SSHサーバが転送する先を指定する)
    ※プライベートIPが10.0.0.24/JupyterNotebookで使うポートが19999(TensorBoardを使う時はポート:6006)
  • ローカル/自動を選択

1.png

開くをクリックしてSSH接続を開始する

手順

まずGPUインスタンスに踏み台サーバより接続してJupyterNotebookを起動する

$ ssh GPU #GPUインスタンスに接続
$ source activate TensorFlow-GPU #Anacondaの仮想環境を起動
$ jupyter notebook #JupyterNotebookを起動

以下のURLにブラウザで接続


http://localhost:19999/?token=×××××××××××××××××××××× 

これでlocalhostのポート:19999にブラウザから接続するとGPUサーバ(プライベートIP:10.0.0.24/ポート:19999)に転送されてブラウザからGPUサーバにあるJupyterNotebookやTensorBoardを使える

参考

【SSH】ポートフォワーディングを使って作業が捗る putty編
SSHポートフォワード(SSHトンネル)【ローカル・リモート・ダイナミック総集編】

続きを読む

OpenFaaSを使ってGo言語でFunctionを書いて、AWSに展開したDocker環境にデプロイするまで

OpenFaaSは聞いたことがあるでしょうか。
まだ生まれて半年ほどしか経っていませんが、GithubStar数は6000を超える勢いで成長している有望なフレームワークです。

2017年10月18日に行われたServerless Meetup Osaka #4でOpenFaaSのことを聞いたので早速試してみました。

どこまでやるかというと、
OpenFaaSのAuthorであるAlex Ellisのブログで紹介されている、OpenFaaSでGo言語の関数を動かして、さらにクラウドに展開するところまでやってみたいと思います。

今回やってみて、日本語の情報がほぼ皆無で、英語でも情報がかなり少なかったので、丁寧に手順を載せておきます。

OpenFaaSいいところ

まとめとして先に良かったことを書いておきます。

  • Dockerイメージになるなら何でも動かせる
  • とはいえ、メジャーな言語のテンプレートを用意している
  • 手軽さは既存のFunction as a Serviceと変わらない

スケール・コストなどの観点はチュートリアルでは評価しきれないので、言及しません。

Faas CLIのインストール

Docker CE 17.05以上がインストールされていることが必要です。

コマンドでさくっとインストールできます。

curl -sSL https://cli.openfaas.com | sudo sh

brewコマンドが使えるなら、

brew install faas-cli

Selection_002.png

OpenFaaSデプロイ環境をローカルに追加

Kubernetesに比べると簡単に扱えると感じたDocker Swarmにデプロイします。

まずはDocker Swarm自体の初期化して、managerとworkerを動作させます。

docker swarm init

以下のコマンドでFaaSスタックをデプロイします。

git clone https://github.com/openfaas/faas && \
  cd faas && \
  git checkout 0.6.5 && \
  ./deploy_stack.sh

このデプロイした環境はどこにいるかというと、Docker Service (Swarm Mode) として動いているので、docker service lsのコマンドで確認できます。

image.png

ローカルのデプロイ環境にはhttp://localhost:8080でアクセスできるので開くと、次のようなFunction管理ポータルが表示されます。
Linuxの場合はhttp://127.0.0.1:8080で開く必要があるかもしれません。

Selection_006.png

Go言語のインストール

こちらの公式インストールガイドを参考にインストールしてください。

v1.8.3かそれ以降が必要です。
gvmでインストールしても問題ありません。

Selection_003.png

$GOPATHが設定されているか確認しておきます。
Selection_004.png

OpenFaaSプロジェクトの生成

まずはプロジェクトフォルダーを作成します。

mkdir -p $GOPATH/src/functions
cd $GOPATH/src/functions

続いてFaaS CLIを使ってプロジェクトテンプレートを生成します。
名前は参考記事通りgohashです。

faas-cli new --lang go gohash

Selection_005.png

プロジェクトの中身を確認する

gohash.ymlファイルにはテンプレートで作成されたFunctionとローカルの実行環境についての設定が書き込まれています。

gohash.yml
provider:
  name: faas
  gateway: http://localhost:8080

functions:
  gohash:
    lang: go
    handler: ./gohash
    image: gohash

gohash/handler.goにはHello Worldなコードが書かれています。

gohash/handler.go
package function

import (
    "fmt"
)

// Handle a serverless request
func Handle(req []byte) string {
    return fmt.Sprintf("Hello, Go. You said: %s", string(req))
}

そしてtemplate内には、各言語のテンプレートもありますが、Go言語のものがちゃんとあります。
main.goではOpenFaaSの仕様通り、 STDIN を受け取って、対応するFunctionを呼び出した結果を STDOUT に送るというシンプルな作りとなっています。

template/go/main.go
package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "os"

    "handler/function"
)

func main() {
    input, err := ioutil.ReadAll(os.Stdin)
    if err != nil {
        log.Fatalf("Unable to read standard input: %s", err.Error())
    }

    fmt.Println(function.Handle(input))
}

Dockerfileが各言語の環境ごとに用意されていて、ミニマルな実行環境を作成し、開発者が用意したFunctionコードをコンテナ内に格納してから最後にWatchdogを起動するという動きになっているようです。

WatchdogはGo言語で書かれた小さなHttpサーバーです。

template/go/Dockerfile
FROM golang:1.8.3-alpine3.6
# ---------- 略 -----------
WORKDIR /go/src/handler
COPY . .
# ---------- 略 -----------
CMD ["./fwatchdog"]

まずはデプロイしてみる

テンプレートを導入した時点で、環境構築が無事に完了しているか確認するために、HelloWorldのままデプロイしてみます。

faas-cli build -f gohash.yml
faas-cli deploy -f gohash.yml

BuildはDockerのイメージをダウンロードするところから始まるので、最初の実行は1分ほど待つかもしれません。

とくにエラーが表示されずに、
Selection_009.png
という風な表示がされたら成功です。

http://localhost:8080にアクセスしてgohashが追加されているか確認します。
左のFunction一覧からgohashを見つけたら適当なRequest bodyを打ち込んで INVOKE します。

Selection_007.png

これで無事にデプロイできることが確認できました。

Functionを実装していく

今回はgo1.9を使ったので、コンテナ内のgoも同じバージョンにしておきます。
今回のコードでは変更しなくても特に問題にはならないと思います。
コンテナ生成Dockerfileを書き換えてしまいます。

template/go/Dockerfile変更前
FROM golang:1.8.3-alpine3.6
template/go/Dockerfile変更後
FROM golang:1.9-alpine3.6

go言語のパッケージ管理ツールとしてdepをインストールします。

go get -u github.com/golang/dep/cmd/dep

そして、Goのデータ(Struct)からハッシュを生成するstructhashdepを使ってインストールします。
ただし、faas-cliがDockerコンテナをビルドするときに、template/go/をワーキングディレクトリとしてビルドを行うため、depの実行はこのディレクトリに移動して行う必要があります。

cd template/go/
dep init
dep ensure -add github.com/cnf/structhash

こうすると、Gopkg.lockGopkg.tomlvernder/template/go/以下に生成されます。
ちなみに、gvm環境だとdep ensureでライブラリがうまくインストールされないことがありますが、goのコードがビルドされるのはコンテナ内なので、一応そのまま進めても大丈夫です。

きちんと開発を進める場合はgvm linkthisdepがしっかりと使えるようにします。

それでは、受け取った文字列データからハッシュを生成するコードに変更しましょう。

gohash/handler.go
package function

import (
    "fmt"

    "github.com/cnf/structhash"
)

// S is sample struct
type S struct {
    Str string
    Num int
}

// Handle a serverless request
func Handle(req []byte) string {
    s := S{string(req), len(req)}

    hash, err := structhash.Hash(s, 1)
    if err != nil {
        panic(err)
    }
    return fmt.Sprintf("%s", hash)
}

プロジェクトのデプロイ

では、作成したコードをデプロイしてみましょう。

faas-cli build -f gohash.yml
faas-cli deploy -f gohash.yml

ポータルの実行結果はFunctionのデプロイで新しいものに置き換えたので結果が変わっています。

Selection_010.png

また、もちろんAPI URLも用意されているので、直接呼び出すこともできます。

curl -X POST -d "てすとめっせーじ" http://localhost:8080/function/gohash

Selection_011.png

テストを追加する

テンプレートのDockerfileにはgo testでテストを実施しているのですが、今のところテスト用のgoファイルは生成されないようです。

今は自分で作りましょう。

touch gohash/handler_test.go
gohash/handler_test.go
package function

import "testing"

func TestHandleReturnsCorrectResponse(t *testing.T) {  
    expected := "v1_b8dfcbb21f81a35afde754b30e3228cf"
    resp := Handle([]byte("Hello World"))

    if resp != expected {
        t.Fatalf("Expected: %v, Got: %v", expected, resp)
    }
}

テストを作ったところで、わざとgohash Functionを間違えて修正してしまいましょう。

handler.go修正前
hash, err := structhash.Hash(s, 1)
handler.go修正ミス
hash, err := structhash.Hash(s, 2)

この状態で再びビルドを実行します。

faas-cli build -f gohash.yml

ちゃんとビルド中にテストで失敗してくれます。
Selection_012.png

コードを元に戻してビルドが成功することを確認します。

DockerHubにビルドしたイメージをPUSH

リモート環境でOpenFaaSを動作させるためには、FunctionのDockerイメージをDockerHubまたは別のレジストリに登録しておく必要があります。

まずは、[DockerHubのユーザ名]/gohashとなるように、gohash.ymlを書き換えます。

gohash.yml書換前
    image: gohash
gohash.yml書換後
    image: gcoka/gohash

Docker Hubの登録が済んでいれば、

docker login

でログインし、

faas-cli push -f gohash.yml

でビルドしたイメージをPUSHします。

AWSにデプロイしてみる

AWS EC2コンソールで SSH KeyPairsを作成しておいてください。
ssh-addもお忘れなく。

ssh-add ~/.ssh/yourkey.pem

AWSにDockerをデプロイするためのテンプレートが用意されているので、ここにアクセスして、
Deploy Docker Community Edition (CE) for AWS (stable)をクリックします。
use your existing VPCを選択すると、Docker用ネットワークの設定をいろいろやらないといけなくなり、VPC内のネットワーク構築の知識が必要となるようです。

https://docs.docker.com/docker-for-aws/#docker-community-edition-ce-for-aws

以下の設定は環境に合わせて変更が必要です。

  • SSHキーにKeyPairsで作成したものを指定。

また、このテンプレートでのCloudFormation実行には、以下のCreateRoleが必要です。
正確な一覧はこちら

  • EC2 instances + Auto Scaling groups
  • IAM profiles
  • DynamoDB Tables
  • SQS Queue
  • VPC + subnets and security groups
  • ELB
  • CloudWatch Log Group

特に設定は変更していません。
デプロイを試すだけなので、Swarm ManagerとWorkerの数は1ずつにしました。

Selection_029.png

CloudFormationのStackデプロイが完了したら、デプロイ結果のOutputsタブから、Swarm Managerのインスタンスへのリンクが参照できるので、開きます。
Selection_030.png

Selection_031.png

このインスタンスにSSH接続を行います。
ユーザーはdockerを指定します。

ssh docker@54.159.253.49

OpenFaaSのスタックを導入するために、Gitが必要なので、インストールします。

中身はAlpine Linuxなので、apkコマンドでパッケージをインストールします。

sshコンソール
sudo apk --update add git

ローカルでにインストールしたときと同じコマンドですが再掲。

sshコンソール
git clone https://github.com/openfaas/faas && \
  cd faas && \
  git checkout 0.6.5 && \
  ./deploy_stack.sh

ではOpenFaaSスタックが無事デプロイされているか確認します。

AWSに構築したテンプレートはインターネットからはLoadBalancerを通してアクセスできるので、LoadBalancerのURLを調べます。DNS name: に表示されているものがそれです。

Selection_034.png

URLがわかったら、ポート8080を指定してアクセスします。

Selection_035.png

うまくいっていることを確認したらAWSにデプロイします。
--gatewayオプションを使えばgohash.ymlファイルを書き換える必要がありません。

faas-cli build -f gohash.yml --gateway http://your.amazon.aws.loadbalancer.url:8080

Selection_038.png

Selection_039.png

無事にAWSで動きました。

トラブルシューティング(詰まったところ)

faas-cli buildしてもコード変更が反映されない

--no-cacheをつけることで、すべてのビルドをやり直してくれます。

faas-cli build -f gohash.yml --no-cache

structhashパッケージがvenderディレクトリにコピーされない

$GOPATHが正しく設定されているか確認してください。

gvmを使ってgoをインストールしている場合は、$GOPATH/src/functionsgvm linkthisを実行すると解決するかもしれません。

AWS CloudFormationのデプロイに失敗する

use your existing VPCのテンプレートを使っている場合は、使わないでVPCの作成もDockerテンプレートに任せてください。

AWSにデプロイしたFunctionを実行しても500: Internal Server Errorになる

Docker HubにDockerイメージをPUSHしたか確認してください。

ちゃんと動いているかわからない・・・

docker serviceとして動いているのでdockerコマンドからいくつか情報を得ることができます。

指定したFunctionのプロセス動作情報を表示
docker service ps gohash
指定したFunctionのログを表示
docker service logs gohash
gatewayのログを表示
docker service logs func_gateway

最後に

Docker SwarmはMicrosoft Azure Container Serviceもサポートしているのですが、完全なマネージドの場合OpenFaaSが必要とするDockerバージョンが足りていないようです。

今回はDocker Swarmに対してデプロイしましたが、Kubernetesもサポートしているので、そちらも試してみたいと思います。
Kubernetesの場合は、Swarmよりもホスティング対応しているクラウドがいくつかあるようなので、期待が持てますね。

情報がとても少ないので、どんどん試してどんどん情報公開していきましょう!

続きを読む

Proxyが厳しい企業内からも利用できるJupyter NotebookをAWS上に用意する

やりたいこと

  • Deep Learning向けのAIMを、Amazon AWSのEC2で動かす
  • Proxy内からもアクセスできるように、Jupyter NotebookをPort443で動かす
  • 通常は安く動かし、必要なときだけパワフルなGPUで動かす
    • インスタンスタイプを変更したらJupyter Notebookが自動で起動
    • インスタンスタイプを変更してもIPアドレスが変わない

Machine Learning や Deep Leaning を学習していると、自分のPCではパワーが足りなかったり、複数の環境を整えるために容量が足りなくなってきたりします。また、時間がかかる処理をさせている時には、コーヒーを飲みながらサクサクとWebサーフィンして待ちたいです。

そこでAmazonのAWS上にEC2インスタンスとして環境を作ります。Lazy Girlの記事を見ると、まさにDeep Learning向けのAMIが用意されている。GPUも使えます。

A Lazy Girl’s Guide to Setting Up Jupyter on EC2 for Deep Learning

Deep Learning AMIを起動

Lazy Girlの記事に従ってセットアップし、デフォルトのPort 8888 できちんとJupyter Notebookにアクセスできることを確認する。

なお、

source src/anaconda3/bin/activate root

をするだけで、

> which jupyter
~/src/anaconda3/bin/jupyter

となったので、.bash_profile にPATHを追加するくだりは必要なかった。

Port 443 で Jupyter Notebookを起動

Portを8888から、Proxyを通過できる443へ変更します。

nano ~/.jupyter/jupyter_notebook_config.py

c.NotebookApp.port = 443

そのままubuntuユーザでjupyter notebookを起動させようとすると、443のような低い番号のポートはダメだと怒られるので、rootで起動します。

sudo jupyter notebook --allow-root

これで厚いProxyの壁に阻まれた会社内からでもJupyter Notebookへアクセスして学習を続けられます!

自動起動の設定

インスタンスタイプを変更するには、一度EC2インスタンスをStopする必要があります。
自動的にJuypter Notebookが立ち上がるようにserviceとして登録しておくと便利です。
(会社のProxyがPort 22を通してくれないので、SSHして手動で起動させられない問題も解決)

sudo nano /etc/systemd/system/jupyter.service

[Unit]
After=network.target

[Service]
ExecStart=/home/ubuntu/start_jupyter.sh

[Install]
WantedBy=default.target

sudo chmod 664 /etc/systemd/system/jupyter.service

nano /home/ubuntu/start_jupyter.sh

#!/bin/bash

source /home/ubuntu/src/anaconda3/bin/activate root
cd /home/ubuntu/notebook
jupyter notebook

chmod 744 /home/ubuntu/start_jupyter.sh

サービスはrootユーザで起動するので、ubuntuユーザからsudoで起動する場合とは挙動が違うようです。rootユーザとして起動したときに読み込まれるjupyter_notebok_config.pyファイルを用意してあげます。

sudo su
>/home/ubuntu# cd
>~# mkdir .jupyter
>~# cp /home/ubuntu/.jupyter/jupyter_notebook_config.py /root/.jupyter/
>~# exit 

サービスを登録してスタート。きちんと動いていることを確認。

~$ sudo systemctl enable jupyter.service
~$ sudo systemctl start jupyter.service
~$ sudo systemctl status jupyter.service

Elastic IP でIPを固定

EC2インスタンスを再起動すると、IPアドレスが変わってしまいます。
Elastic IPサービスを使用すると、同じIPアドレスでアクセスできるようになります。

EC2 Management Console -> Elastic IPs -> Allocate new address

なお、EC2インスタンスをSTOPしている時にはElastic IPサービスの利用料が掛かります。(EC2インスタンスにattachされている時にはElastic IPサービスの部分は無料)

N.Virginiaでの料金だと、倹約のためにEC2インスタンスをSTOPしていても月に$3.6掛かります。t2.nanoをずっと動かし続けた$4.18とほとんど変わらない。

Instance Type Monthly $
stopped 3.60
t2.nano 4.18
t2.micro 8.35

おまけ (System Shell Command)

会社のProxyは非常に厳しく、Port 22を通してくれません。SSHでサーバにアクセスしてGitHubからexampleをダウンロードしたり、必要なモジュールをインストールしたりしたい時に困ります。

でもJupyter NotebookにさえWebブラウザからアクセスできればなんとかなります。

Jupyter NotebookのPython promptでは、!ping www.bbc.co.ukのように「!」で行をスタートすればシステムシェルコマンドが打てます。

Screen Shot 2017-10-21 at 10.40.29.png

続きを読む

RedashをAMIから起動してみた

公式AMIからインスタンスの起動

https://redash.io/help-onpremise/setup/setting-up-redash-instance.html

から AMI を選択します。Region ap-northeast-1 の AMI リンクをクリックするとインスタンスタイプを選択する画面に遷移するので、適当なインスタンスタイプを選択します。

1年間の無料枠を使っているので無料で使える t2.micro にしました。

キーペアを設定して起動します。

アクセス設定

マネジメントコンソールからインスタンスのセキュリティーグループのインバウンドで HTTP アクセスを適切に許可します。

これでブラウザからインスタンスのIPにアクセスすればページが表示されます。

internal_server_error.png

Internal Server Error(500エラー)ですね。サービス側に問題がありそうなので確認します。

サーバ側設定

起動したインスタンスに SSH ログインします。

とりあえずサービスを再起動してみます。

$ sudo supervisorctl restart all
redash_server: stopped
redash_celery_scheduled: stopped
redash_celery: stopped
redash_celery: started
redash_server: started
redash_celery_scheduled: started

再度ブラウザをリロードしてみますが、Internal Server Error に変化はありません。

supervisord のログを確認します。

$ less /var/log/supervisor/supervisord.log

が、怪しそうなログは出ていません。Redash が使っているサービスの起動状態をひとつひとつ確認します。

PostgreSQL のプロセスを確認します。

$ ps aux | grep -i postgres
ubuntu   21547  0.0  0.0  12948   932 pts/0    S+   13:47   0:00 grep --color=auto -i postgres

見つからないので、PostgreSQL が起動していない事が原因のようです。ログを確認します。

$ less /var/log/postgresql/postgresql-9.5-main.log
2017-10-16 13:32:30 UTC [1352-1] LOG:  database system was shut down at 2017-08-13 12:39:56 UTC
2017-10-16 13:32:30 UTC [1352-2] LOG:  MultiXact member wraparound protections are now enabled
2017-10-16 13:32:30 UTC [1351-1] LOG:  database system is ready to accept connections
2017-10-16 13:32:30 UTC [1356-1] LOG:  autovacuum launcher started
2017-10-16 13:32:31 UTC [1361-1] [unknown]@[unknown] LOG:  incomplete startup packet
2017-10-16 13:34:33 UTC [1351-2] LOG:  received fast shutdown request
2017-10-16 13:34:33 UTC [1351-3] LOG:  aborting any active transactions
2017-10-16 13:34:33 UTC [1705-1] redash@redash FATAL:  terminating connection due to administrator command
2017-10-16 13:34:33 UTC [1704-1] redash@redash FATAL:  terminating connection due to administrator command
2017-10-16 13:34:33 UTC [1356-2] LOG:  autovacuum launcher shutting down
2017-10-16 13:34:34 UTC [1353-1] LOG:  shutting down
2017-10-16 13:34:34 UTC [1353-2] LOG:  database system is shut down
2017-10-16 13:34:53 UTC [19851-1] FATAL:  could not map anonymous shared memory: Cannot allocate memory
2017-10-16 13:34:53 UTC [19851-2] HINT:  This error usually means that PostgreSQL's request for a shared memory segment exceeded available memory, swap space, or huge pages. To reduce the request size (currently 148488192 bytes), reduce PostgreSQL's shared memory usage, perhaps by reducing shared_buffers or max_connections.

FATAL エラーが出てますね。その前にログの時刻が見づらいので、タイムゾーンを日本時間に変更します。

$ sudo timedatectl set-timezone Asia/Tokyo
$ date
Mon Oct 16 22:53:17 JST 2017

JST に変わりました。

先ほどの PostgreSQL のエラーは割り当てられたメモリサイズが大きいというもののようです。

$ sudo vi /etc/postgresql/9.5/main/postgresql.conf

#max_connections = 100
max_connections = 50

#shared_buffers = 128MB
shared_buffers = 32MB

少ないですね。再起動します。

$ sudo /etc/init.d/postgresql restart
Restarting postgresql (via systemctl): postgresql.service.

プロセスを確認します。

$ ps aux | grep -i postgres
postgres 21785  0.0  1.5 186840 15880 ?        S    23:02   0:00 /usr/lib/postgresql/9.5/bin/postgres -D /var/lib/postgresql/9.5/main -c config_file=/etc/postgresql/9.5/main/postgresql.conf
postgres 21787  0.0  0.3 186840  3832 ?        Ss   23:02   0:00 postgres: checkpointer process
postgres 21788  0.0  0.3 186840  3832 ?        Ss   23:02   0:00 postgres: writer process
postgres 21789  0.0  0.3 186840  3832 ?        Ss   23:02   0:00 postgres: wal writer process
postgres 21790  0.0  0.6 187244  6104 ?        Ss   23:02   0:00 postgres: autovacuum launcher process
postgres 21791  0.0  0.3 148544  3128 ?        Ss   23:02   0:00 postgres: stats collector process
ubuntu   21808  0.0  0.1  12948  1092 pts/0    S+   23:02   0:00 grep --color=auto -i postgres

起動した!

ブラウザからアクセスすると。

welcome_redash.png

表示された!

Admin ユーザを登録すればとりあえず使えるようになります。

このままだとメール設定などが出来ていなので、必要であればヘルプ

https://redash.io/help/

などを参考にします。

ちなみに

最初に試した時は、次のような en_US.UTF-8 ロケールが無いというエラーが出ていました。

2017-10-09 08:38:28 UTC [2801-1] redash@redash FATAL:  database locale is incompatible with operating system
2017-10-09 08:38:28 UTC [2801-2] redash@redash DETAIL:  The database was initialized with LC_COLLATE "en_US.UTF-8",  which is not recognized by setlocale().
2017-10-09 08:38:28 UTC [2801-3] redash@redash HINT:  Recreate the database with another locale or install the missing locale.

確認すると確かに無い。

$ locale -a
C
C.UTF-8  # en_US.utf8 がない
POSIX

そのため、次のようにして en_US.UTF-8 をインストールして起動しました。

$ sudo locale-gen en_US.UTF-8
$ locale -a
C
C.UTF-8
en_US.utf8
POSIX

この記事を書くために最初から通して試してみたら en_US.utf8 ローカルが入っていて、再現しませんでした。

Issue を立てたのですが、勘違いだった可能性が高いのでそっと閉じました。

続きを読む

sshの際にルートユーザー権限を付与する

やりたかったこと

以前に書いたEC2内に作業用ユーザーを追加して、新規鍵を元にSSH接続する手順の続きのような感じなのだけれど、scpやrsyncなどでファイルをアップロードするときに、他社用に作ったユーザーでは権限がないと言われてしまうので、scpやrsyncを行えるように権限周りの設定をちょっと変更した。

手順

作成したユーザーでコマンド実行時にpasswordを入力しなくても大丈夫なようにする。
なお前回の記事の続きのようなものなので、ユーザーはhogeuserを例とする
EC2インスタンス内で以下を実行。
生成するファイル名はユーザーの名前なので、今回だとhogeuserというファイルを生成する

// ルートユーザーになる
$ sudo -i

// ファイルを作成し、編集を行う
$ vi /etc/sudoers.d/hogeuser

// 以下を追記
hogeuser ALL=(ALL) NOPASSWD:ALL

// 以上入力後保存して終了

上記実行後scprsyncコマンドが使えるようになる

続きを読む

AWSで作成したインスタンスにSSHで接続できないとき

環境

  • MacOS 10.12.6

AWSのインスタンス作成後にSSHコマンドで接続しようとした時に

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for 'my-keypair.pem' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "my-keypair.pem": bad permissions
Permission denied (publickey).

となる場合がある。これは、使おうとしているキーペアのパーミッションレベルが甘すぎだよ、もっと絞って、と言っているのである。

$ chmod 600 my-keypair.pem

とすることでsshコマンドが通るようになる。

続きを読む

カテゴリー 未分類 | タグ

EC2内に作業用ユーザーを追加して、新規鍵を元にSSH接続する手順

はじめに

あるプロジェクトで他社の開発者もEC2インスタンス内で作業する必要が出てきた。
その際、pemファイルを渡さない方法で他社の開発者がSSH接続できる環境を作りたく色々調べた際のメモ。

割とこういう場面ってあるんじゃないかと思う。

目次

  1. EC2内にユーザーを追加
  2. ローカルマシンで鍵の作成
  3. サーバーに公開鍵を設置と設定
  4. ローカルから鍵を元にアクセス

1. EC2内にユーザーを追加する

まずは、他社用のユーザーを追加し、設定する。

例ではhogeuserが他社のアカウントになるので、その部分を適宜変更して進めてみてください

// EC2内でルート権限になる
$ sudo -i

// ユーザー追加
$ useradd hogeuser

// パスワードを設定
$ passwd hogeuser

$ vi /etc/sudoers
vimでsudoersを開きhogeuserに関する記述を追記

## Allow root to run any commands anywhere
root    ALL=(ALL)       ALL
# 以下を追記
hogeuser ALL=(ALL) ALL

編集終わったら、escを押し、:wpを入力してエンター

2. ローカルマシンで鍵の作成

他社の開発者が以下で作成した鍵を元にアクセスをしてもらうために、新規で鍵を作成する。

以下はサーバーではなく自分のPC内で行う

// .sshフォルダがなければ作成
$ mkdir ~/.ssh

// .sshフォルダに入る
$ cd ~/.ssh

// 鍵の作成
$ ssh-keygen -t rsa -f id_rsa_hogeuser

以上で、.sshフォルダ内にid_rsa_hogeuserid_rsa_hogeuser.pubというファイルが生成される。前者が秘密鍵で、後者が公開鍵。


// scpコマンドで公開鍵をアップロード
$ scp -i 〇〇.pem ~/.ssh/id_rsa_hogeuser.pub ec2-user@EC2インスタンスのパブリックIP:/home

3. サーバーに公開鍵を設置と設定


// ec2内に入りルートユーザーになる
$ sudo -i

// ユーザーのディレクトリを作成
$ cd /home

$ mkdir hogeuser

// hogeuserディレクトリに入る
$ cd hogeuser

// .sshディレクトリを作成
$ mkdir .ssh

// 公開鍵をコピーしてリネーム
$ mv /home/id_rsa_hogeuser.pub /home/hogeuser/.ssh/authorized_keys

// ユーザーとグループを変更
$ chown -R hogeuser:hogeuser ./.

// 権限変更
$ chmod 700 .ssh

$ chmod 600 .ssh/authorized_keys

4. ローカルから鍵を元にアクセス

// 秘密鍵を元にアクセス
$ ssh hogeuser@EC2インスタンスのパブリックIP ~/.ssh/id_rsa_hogeuser

上記入力後に作成したパスワードでアクセスが可能。
rootユーザーになりたい場合も同じパスワードでなれる。

続きを読む

AWS初心者がインフラ設計/構築を理解するために、まず最初におさえるべき専門用語 15選

【 はじめに 】 ※現在絶賛執筆中!

~ 現段階 (2017/09/25) では、AWSサービスのことをほとんど知らない ~

今回、AWS初心者の僕がインフラ設計/構築の担当者になった。何事も経験だ!」と、自分から手を挙げたものの、
覚えることが多すぎやしないか?と思いつつ、これも自分の伸びしろだと、、まだまだ伸びる証拠だと
ポジティブに捉えて(本田風)
、絶賛AWSサービスと格闘する毎日を送っている自称ITエンジニアの奮闘記である。

【 現状の課題とその解決策 】

作業を開始してから2週間程度が経過した時点で、このまま場当たり的に知識を身に着けて行くのは、
かなり効率が悪いということに気が付いた。( 自分で言うのも何だが遅すぎないか? :man_tone5: )

もちろん現場で起こっている課題を解決しながら、
場当たり的に問題解決能力を知識を身に着けていくことも重要だと思う。

しかしながら、この局面 (AWSのサービスを全く知らない。インフラに関しての知識はゼロ。) においては、
クラウドの基礎知識を体系的に一からきちんと知識を身に着けていく戦法が有効
だと考える。

理由は、下記の通り。


  • 各単語の関係性についても合わせて学習することにより、単語の忘却曲線をより緩やかにすることができる。
    現状の課題 (1) : 単発だと結構すぐに忘れてしまう。
  • クラウドの全体像を把握するスピードが早くなるので、効率よく知識を吸収することができる。
    現状の課題 (2) : 基礎知識を短期間で習得できるので、後々応用が効きやすい。
  • いきなりAWSコンソール画面を触って間違えてしまうといったような無駄が無くなる。
    現状の課題 (3) : 基礎がないので、想定していないミスをするケースも。。(痛い目に合うのも大事だけどw)

上記のような理由より、自分の知識を蓄積し、常にアップデートしていくため手段 (備忘録) として、
Qiitaに思考プロセス等を書き残していこうと思う。

(他の人がこれを読むことで勉強になるかどうかは分からないですが、、。)

【 対象読者のみなさん 】

  • 業務でインフラを担当することになったけど、どうしたら良いのかイマイチ分からない人
  • インフラ構成図を見て一通り内容を理解しておきたい人
  • AWSインフラに興味があるけど、触ったことがない人

etc ..

【 お願い 】

もし、本記事の内容に「誤り・誤字」があれば、遠慮なくお気軽にご指摘いただければ幸いです。

それでは、AWSでのインフラ構築担当になってまず最初に覚えたワード15選について、
筆者が参考にしたサイト、各概念の分かりやすい表現をPickUp:point_up:!しながら、
ご説明させていただこうと思います。

読んでいただいた方のお役に立てるような記事にしたいと思っていますので、
どうぞ最後までお付き合いください
:grinning: !!!

【 本編 】AWS初心者がインフラ設計/構築を理解するために、まず最初におさえるべき専門用語 15選

まずは、「AWSって何なの?」ってところから。
  
amazon-web-services-logo-large1-e1334297880876.png

00. AWSの基本概念

AWSは、「Amazon Web Service」の略なんだけど、AWSとは?
と何も見ずに語れるほどの知識はないので、この部分に関しては後日アップデートする予定です。

[ 2017/10/13(Fri)時点での、筆者のAWSへ対する認識 ]

クラウドコンピューティングのリソースを提供していて、その上に様々なサービスを乗っけて、
誰でも簡単に?使った分だけの費用(従量課金)でインフラ環境を構築できるサービスってイメージ。

クラウドコンピューティングのリソースというのは、
世界各地にあるAWSが保有しているデータセンターのことなんだけど、、

まず最初に、

どの地域 [リージョン(Region)] のコンピューティングリソースを使用するのか?

ということを決めないといけない。

1. リージョン (Region)

リージョン(Region) 自体は「範囲、領域」を持つ英単語 :point_up:
Amazon クラウドコンピューティングリソース世界各地の多くの場所でホストされており、
これらの世界各地の拠点、物理的に離れている領域のことリージョン(Region)と言います。

2017/10/12(木)時点で、世界中に16個ものリージョン(Region)が存在します。

(以下、「AWS公式サイト」より引用。)

image.png

※今後、さらに5つのリージョンが追加される予定みたいです。(2017/10/12時点)

・中国
・フランス
・香港
・スウェーデン
・米国 (2番目のAWS GovCloudリージョン)

初めてAWSサービスに触れられる方は、とりあえず何も考えずに、
アジアパシフィック(東京リージョン)を選ばれることをお勧めいたします。

※別途リージョン選択についての細かな部分について紹介する記事を書こうと思います。

[参考サイト]


各リージョン内にはかならず2つ以上のアベイラビリティーゾーン (≒データセンター)と呼ばれる拠点があります。

続いては、そのアベイラビリティーゾーンについてご紹介したいと思います。

2. アベイラビリティーゾーン (AZ : Availability Zone)

アベイラビリティーゾーンを物凄く分かりやすく、簡単に言うと、、。

東京リージョン(物理的に離れた地域)= 東京という都市(場所)に、3つの独立したデータセンター(拠点)が存在し、
この各々のデータセンターのことを「アベイラビリティーゾーン(AZ)」と言います。

AWS.jpg

* 1つのリージョン内に2つ以上のアベイラビリティーゾーン(データセンター)が存在するので、
インフラ設計をする際は、複数のアベイラビリティーゾーン(Multi-AZ)を活用することにより、
構築するインフラ/アプリケーションの耐障害性を向上させることができます。

「リージョンとアベイラビリティゾーンに関する概念について」

各リージョンは完全に独立しています。各アベイラビリティーゾーンも独立していますが、
同じリージョン内のアベイラビリティーゾーン同士は低レイテンシーのリンクで接続されています。

リージョンとアベイラビリティーゾーン」より引用

3. VPC (Virtual Private Cloud)

AWSクラウドの論理的に分離した領域 (セクション) を、誰でも簡単に用意することができます。

下図のようなイメージです。

VPC.jpg

この VPC (Virtual Private Cloud) を活用すると自分で定義した仮想ネットワーク内
AWSリソース (ex. EC2,RDS) を起動させることができます。

VPC (Virtual Private Cloud) のIPアドレスは、以下規則で指定することができます。

  • VPC全体で1つのIPアドレスを持つ
  • サブネットでIPアドレス空間を分割する

[ ※注意 ]
ネットワークアドレスは作成後変更不可なので、あらかじめ20ビット以下など、
ある程度のレンジを持つアドレスを設定しておくのが無難です。

[参考サイト]

4. サブネット(Subnet [Public, Private])

サブネットとは、大きなネットワーク (≒VPC) を
複数の小さなネットワークに分割して管理する際の管理単位となる小さなネットワーク (≒サブネット) のこと。

※下図のようなイメージ。

Subnet.jpg

自分で定義したネットワーク(VPC)を複数のネットワークに分割するために使用します。

具体的には、各インスタンスの役割ごとにグループ化 (サブネットに分割) し、
ルートテーブルをアタッチする際などに使われることが多い (きめ細やかなアクセスコントロールが可能) です。

[ パブリックサブネット ][ プライベートサブネット ] の違いについて


まずは、下図をご覧ください!

Subnet2.jpg

上図の通り、インターネットからVPCインスタンスに接続する ためには、
インターネットゲートウェイ (次項で説明) を用意する必要があります。
そして、VPCネットワーク内にあるルーターを介して、各サブネット内のインスタンスへ通信が行われます。

この時、各サブネットにアタッチされているルートテーブル (経路制御表) の内容に沿って、
インターネットからのアクセスを許可するのか、許可しないのかを判断します。

上記の違いで、パブリックサブネット, プライベートサブネットの区別をしています。

  • インターネット(外部ネットワーク)からのアクセスを許可したサブネットを「パブリックサブネット
  • VPC内部の通信のみ許可しているサブネットを「プライベートサブネット

[参考サイト]

5. インターネットゲートウェイ (Internet Gateway)

インターネットゲートウェイは、VPCのインスタンスとインターネットとの間の通信を可能にする
VPCコンポーネント。

こちらのインターネットゲートウェイの役割大きく2つあります。


1. みなさんが作成したVPCネットワークのルートテーブルに、
インターネットへルーティングが可能な宛先を追加すること。

2. パブリックIPv4アドレスが割り当てられているインスタンスに対して、
ネットワークアドレス変換(NAT)を行うこと。


[参考サイト]

6. デフォルトゲートウェイ (Default Gateway)

所属するLANなどの内部ネットワーク (AWS上のサブネット) から、
外部にあるネットワーク(他のサブネットもしくは、インターネット)に通信を行う場合の
出入り口の役割を果たすよう設定されているルーターやコンピューターのことです。

デフォルトゲートウェイは、
ネットワーク上でプロトコル(規約)が異なる複数のデータを相互に変換し通信を可能
にします。

[参考サイト]

7. ルーター(Router)

IP(Internet Protocol)で通信する端末は、まず最初に通信相手が自分と同じネットワーク(同一サブネット内)に
属する端末かどうかを調べ、自身の属するネットワーク外への通信であれば、ルーター(Router)を経由して
通信を行います。

[参考サイト]

8. ルートテーブル (経路制御表:ルーティングテーブル)

ルーターや端末が保持するパケットの配送先に関する経路情報。

VPCの各サブネットをルートテーブル

ルートテーブルの生成・管理方式には、下記2種類が存在します。


・Static Routing (スタティックルーティング)

経路情報を各ルーター内に手動で設定する手法で、
この経路情報は基本的にルート・テーブルより消えることがありません。

・Dynamic Routing (ダイナミックルーティング)

RIP(Routing Information Protocolo)」「OSPF(Open Shortest Path First)
BGP(Border Gateway Protocol)」などのルーティング・プロトコルを用いて、
ルーターが経路情報を自動的に学習する手法で、この経路情報は動的に更新されます。


[参考サイト]

9. NAT (NAT Gateway)

NATとは、Network Address Translationの略称であり、IPアドレスを変換する技術です。
一般的には、プライベートIPアドレスをグローバルIPアドレスに変換する技術とされています。

ex.
企業LAN内のクライアントPCがインターネットに接続する場合に、プライベートIPアドレスを
グローバルIPアドレスに変換する必要があります。

この時に必要になる仕組みが、NAT(NAT:Network Address Translation)です。

10. 踏み台(Bastion)サーバー

メンテナンスの為の接続経路用途で用意されるサーバーのことを指します。

具体的には、アプリサーバー自体が外部(インターネット)から直接SSH接続を受け付けること自体、セキュリティの観点からもよろしくないので、外部からのSSH接続は、アプリサーバーとは別の専用サーバーが受け付けるべきです。そして、そのサーバーからアプリサーバーにSSH接続するといった二段階接続の構えを取ることでセキュアな環境を実現することができます。この時に用意するサーバーが上記の踏み台(Bastion)サーバーとなります。

また、踏み台サーバーは管理者が使用する時間帯以外は停止状態にしておくことにより、
部外者が勝手に侵入するといった心配もなくなるので、セキュアな構成を実現できる仕組みとなります。

(以下、近日中アップデート予定)

11. セキュリティグループ

異なるセキュリティグループに属するインスタンスと通信を行う際に、
トラフィックの制御を行う仮想ファイアウォールとして機能します。

※セキュリティグループはサブネット単位ではなく、インスタンス単位で設定する必要があります。

また、インスタンスを起動 ( 新規作成 ) する際には、対象のインスタンスと1つ以上のセキュリティグループとの
関連付けが必須となります。

[参考サイト]

12. ElasticIP

13. VPCエンドポイント

[参考サイト]

01. アクセスポリシー

AWSでのアクセスポリシーオプション (アクセス制御 ) は、大きく2つに分類されます。

  • リソースベース(S3のバケットやオブジェクトに対して)のポリシー
  • ユーザーポリシー

どのようなアクセス制御をしたいかによって、
リソース自体に閲覧等の権限を付けるもの (リソースベースのポリシー)
ユーザー単位で操作可能範囲を決めるもの (ユーザーポリシー)など、
柔軟性の高いアクセスポリシー設定が可能です。

本記事では、それぞれ代表的なものを一つずつ紹介したいと思います。

14. IAM (Identity and Access Management) 【 ユーザーポリシー 】

ユーザーに対して、AWSへのアクセスを安全に制御するための仕組み。 AWSコンソール画面から設定が可能で、
IAM (Identity and Access Management) の利用自体が課金対象になることはありません。 (基本無料)

IAMを使用することにより、下記のようなケースでアクセス制御を行うことができます。

  • どのユーザーがAWSリソースを使用できるか?
  • (リソースを使用できる場合)どのような方法で使用することが可能か?

[参考サイト]

15. ACL (Access Control List) 【 リソースベースのポリシー 】

リソースごとに少しずつ設定方法が異なるみたいですが、今回はS3()のバケットやオブジェクト
に対してのアクセス管理について紹介したいと思います。

各リソースには、サブリソースとして、ACLをアタッチする必要があります。
このACLによって、アクセスが許可されるAWSアカウントまたはグループと、アクセスの種類が定義されます。

当該リソースに対するリクエストを受信すると、Amazon S3はアタッチされたACLの内容を調べて、
リクエスト送信者がACLの内容を満たしているか判断します。

[参考サイト]

00. ランク外だけど重要なキーワード

16. シークレットキー

[ 筆者失敗談 ]

[※注意!] するほどでもない話。

もし、AWSのアカウントを取得されている方でこれからEC2インスタンスを生成するという方、
S3に新しいバケットを作られるという方はですね、今一度AWSコンソール画面右上のリージョン設定を
ご確認いただくことをお勧めいたします。

image.png

僕は気が付いたら、米国西部 (オレゴン) のリージョンでEC2インスタンスを立ち上げていて、
他のEC2インスタンス(東京リージョンで作成済み)がコンソール画面で確認できないので凄く焦りましたw

みなさんはこんな凡ミスはしないとは思いますが、一応ここに間違えた人間がいるので、記載しておきます。

最後に

今後記事内容をアップデートしていきながら、自分自身もAWSへの知見を深められたらなと思います。
最後までお読みいただき、ありがとうございました (^^)/

続きを読む