IT・ビッグデータ徒然ブログ

関西でインフラ、データ基盤系のエンジニアになりたい

Ubuntu16.04にCDH5を入れる

CDH5をインストールするを読んで、Ubuntuでやろうとしたら思いの外つまづいたので、備忘録代わりに残しておきます。
(今更こんな方法でHadoop入れる人いないと思うけど。。。)

環境

Javaのインストール

ひとまず、java8を先に入れて、PATHを通しておきます。

sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get -y install oracle-java8-installer
cat << EOF >> ~/.bashrc
JAVA_HOME=/usr/lib/jvm/java-8-oracle
PATH=$PATH:$JAVA_HOME/bin
export JAVA_HOME
export PATH
EOF
source ~/.bashrc

Hadoopリポジトリ登録

ここでおおきく躓いた。。。
まず、そもそもリポジトリの概念がCentとUbuntuで異なるので、Ubuntu用のファイルをとってこないと行けない。

# trustyはUbuntu14.04だけど、16.05用のディレクトリがないのでこっちから落としてくる
sudo wget https://archive.cloudera.com/cdh5/one-click-install/trusty/amd64/cdh5-repository_1.0_all.deb

その後、debパッケージを開く

sudo dpkg -i cdh5-repository_1.0_all.deb

次に、リポジトリのキーをUbuntuに入れてあげる。

sudo curl -s https://archive.cloudera.com/cdh5/ubuntu/trusty/amd64/cdh/archive.key | 
sudo apt-key add -

これで準備は完了。。。と思いきや、、、ここでまた一つ問題が・・・

インストールするバージョンを指定する

というのも、このままなにもせずに素直にapt-getすると最新版のCDHが入ってしまう。
今回は都合によりバージョン5.12に指定したいので、
/etc/apt/sources.list.d配下のcloudera-cdh5.listファイルを修正する

cd /etc/apt/sources.list.d
cp cloudera-cdh5.list cloudera-cdh5.list.orig

cat << EOF > cloudera-cdh5.list
deb [arch=amd64] https://archive.cloudera.com/cdh5/ubuntu/xenial/amd64/cdh xenial-cdh5.12 contrib
deb-src https://archive.cloudera.com/cdh5/ubuntu/xenial/amd64/cdh xenial-cdh5.12 contrib
EOF

ポイントは指定するURLで

https://archive.cloudera.com/cdh5/ubuntu/<Ubuntuのバージョン>/amd64/cdh <Ubuntuのバージョン> - <インストールするCDHのバージョン>

みたいにする。

今回は、
+ Ubuntu : 16.04(xenial) + Hadoop : CDH5.12
だったので上のような書き方になった。

ちなみに、書き方を見たい場合は、 https://archive.cloudera.com/cdh5/ubuntu/バージョン>/amd64/cdh/confにあるdistributionsファイルの中のCodenameを見ればわかる。

例: https://archive.cloudera.com/cdh5/ubuntu/xenial/amd64/cdh/conf/distrobutionsの一部

Origin: Cloudera
Label: Cloudera
Codename: xenial-cdh5.11.1
Version: 16.04
Architectures: amd64 source
Components: contrib
Description: Cloudera nightly packages for xenial
SignWith: 02A818DD

Origin: Cloudera
Label: Cloudera
Codename: xenial-cdh5.12.0
Version: 16.04
Architectures: amd64 source
Components: contrib
Description: Cloudera nightly packages for xenial
SignWith: 02A818DD

Origin: Cloudera
Label: Cloudera
Codename: xenial-cdh5.12
Version: 16.04
Architectures: amd64 source
Components: contrib
Description: Cloudera nightly packages for xenial
SignWith: 02A818DD

Hadoopインストール&起動

あとは素直にHadoopを入れて動かすだけ。

sudo apt update
sudo apt-get install -y hadoop-conf-pseudo

sudo -u hdfs hdfs namenode -format

sudo systemctl start hadoop-hdfs-namenode hadoop-hdfs-datanode hadoop-hdfs-secondarynamenode

sudo /usr/lib/hadoop/libexec/init-hdfs.sh


sudo systemctl restart hadoop-hdfs-namenode hadoop-hdfs-datanode hadoop-hdfs-secondarynamenode

sudo systemctl start hadoop-yarn-resourcemanager hadoop-yarn-nodemanager

結論

Cloudera ManagerとCloudera Directorは正義。

LDAP基本の基本解説という名のメモ(初心者向け)

久しぶりに仕事でLDAPをいじろうと思ったら、すっかり言葉や仕組みを忘れてしまっていたので、再勉強のついでにLDAPのことをメモ代わりに書き残しておきます。

参考書はこちら
入門LDAP/OpenLDAP ディレクトリサービス導入・運用ガイド 第3版

What is LDAP

Lightweight directory access protocolの略称。
その名の通り、プロトコル。(FTPとかHTTPと同じ類)
もともとあったDAPというサービスを軽量化させて一般的に使えるようにしたもの。
ユーザーやパスワード等を管理するために使われる。(RDBではない)

用途

  • 社内のITサービスにおけるユーザー管理
  • ユーザーにまつわる認証、認可関連

LDAPにおけるデータ構造

エントリ

DBでいうところのテーブルのようなもの。
組織エントリとか、在庫エントリとか。
基本的にKey/Value形式のような形で、属性名/属性値を設定する。

属性名 属性値
名前 山田一
住所 大阪府〇〇
電話番号 △△△△

オブジェクトクラス

DBでいうカラムの定義。
各属性に対して、どんな情報を入れるのかを定義しておく。
例えば電話番号に文字列が入るとおかしいなどバリデーションができる。(属性構文)
これらをまとめたものをスキーマと呼ぶ。

DIT(ディレクトリインフォメーションツリー)

基本的にLDAPでは各ユーザーを階層構造で定義しておき、芋づる式でユーザーを検索する。
その階層を定義するのがDITとなる。
例: ◯◯会社の△△部□□課の山田さんというユーザーは、 + 会社 + 部 + 課 という3つの階層が定義されており、その中で管理されている。 (ここでいう△△部とか□□課は他の部や課と区別するということでRDN(Relative Distinguished Name)と呼ばれる)

  • DITでよく出る用語 |用語|概要| |----|----| |dn|識別名| |objectClass|そのまま| |dc|ドメインを構成する要素| |o|組織名| |ou|組織単位| |cn|名称|

さっきの例をDITの用語で表現すると、

DN: cn=山田さん,ou=□□課,ou=△△部,dc=◯◯会社

みたいになる(はず)

上記参考書のp26の図がすごくイメージがしやすくなります。

LDAPを使ったアクセス認証

LDAP使用時におけるユーザーのアクセス認証については、
+ 各dnにたいしてパスワードを設定する + SASL等のSSOと連携 + Linuxのユーザー権限と組み合わせ

が可能。

LDAPを使ったユーザー検索

ユーザー検索では、 + どの階層に属しているユーザーを検索するか(base) + 指定した階層からどこまで掘り下げて検索するか(one,child) を設定する。
またフィルタを設定することで検索から必要なユーザーだけ抽出も可能。

LDAP更新

LDAPでは追加、更新、削除ができるが、これらはLDIFと呼ばれるフォーマットで設定する

とりあえずここまで。
次回くらいに簡単に構築したものを載せてみようかな。

Lambda用にテンポラリーアクセスキーを作成する(あくまで試行錯誤の過程)

以前期限付きURLをLambdaで作成する方法を紹介しました。
そこで最大7日間まで設定できると高をくくったのですが、
いざ使ってみるとものの数時間で、

This token has expired

的なエラーが返ってきます。。。
念のため、何度か確認したのですが、設定した値より前にダメになりました。
何か問題がないかと確認したところ、以下の仕様っぽいです。

  • Lambdaで期限付きURLを発行するとテンポラリのアクセスキーが生成される。
  • 期限より前にテンポラリーアクセスキーの期限がterminateされるとURLも使えなくなる。

これは面倒ですね。。。
であれば、以下のように、

import boto3
from boto3.session import Session



def lambda_handler(event, context):

  BUCKET = '<バケット>'
  KEY = '<ファイル名(パスを含む)>'
  
  #持っているアクセスキーとシークレットキーを指定
  session = Session(aws_access_key_id = '<アクセスキー>',
                aws_secret_access_key = '<シークレットキー>',
                region_name = 'ap-northeast-1')

  s3 = session.client('s3')

  url = s3.generate_presigned_url(
      ClientMethod = 'get_object',
      Params = {'Bucket' : BUCKET, 'Key' : KEY},
      ExpiresIn = 6048000,
      HttpMethod = 'GET'
    )

  print(url)

とすれば問題ないのですが、これだとアクセスキーが完全に露出してしまうのでセキュリティ的に怖いです。

なので、一時的なアクセスキーを作成する方法をさくっと調べてみました。

アクセスキーの作り方 + assumeroleのポリシーを作成 + ポリシーをLambda実行するロールに割り当て + boto3でassumeroleを実行(今回はLambdaでやってみる)

assumeroleポリシーを作成

まずはIAMに移動し、ポリシーで以下のようなポリシーを作成します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "<sidの値>",
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::<数字>:role/<ロール名>"
        }
    ]
}

ポリシーをLambda実行するロールに割り当て

これはそのままIAMのロールにてポリシーを割り当てを設定すればよいです。

boto3でassumeroleを実行

今回はLambdaで以下のようなプログラムを作ってみました。

import boto3

def lambda_handler(event,context):

    sts = boto3.client('sts')
    result = sts.assume_role(
                 RoleArn = '<assumeポリシーで設定したロールのARN>',
                 RoleSessionName = '<適当なセッション名>',
                 DurationSeconds=3600
     )

    print(result)

これをテストで動かしてみると結果にアクセスキーが生成されます。

課題

しかし、上記プログラムでDurationSecondsの値を3600(1時間)以上に設定するとエラーが発生。

"errorMessage": "An error occurred (ValidationError) when calling the AssumeRole operation: The requested DurationSeconds exceeds the MaxSessionDuration set for this role.",

boto3のリファレンスを見てみると、、、

  • DurationSecondsの最大値は3600

うーんこれは困りましたね。。。
文章ではSessionSecondsの設定で12時間まで引き上げられるっぽいのですが、この関数のパラメータとしては渡せないので、どうしていくかこれから考えてみます。

起動させるたびにIPが変わって鬱陶しいあれをなるべくお金をかけずに解決する

前ふり

AWSクラウドでサーバを立てる時に気になるお金。
なるべく課金を減らすために必要なときだけ立てて、いらなければ落とすなんてことをしますよね。
でも落とした後に起動するとやっかいなのがIPアドレスの変更。
毎回毎回アドレスが変わってしまうとssh config等の設定を変えないといけなかったりして面倒なんですよね。
かといってElasticなIPを使うとそれでもお金がかかってしまうので嫌だ。。。
というわけで、なるべくお金をかけずにかつ設定をなるべく変えないでサーバを扱う方法を紹介します。
※今回の例はあくまで検証や遊びでサーバを立てて使う人用の方法です。本番システムでの利用は推奨しません。

やること

  • VPCを作成
  • パブリックサブネットとプライベートサブネットを立てる
  • インターネットからパブリックサブネットにアクセスさせる設定
  • パブリックサブネットに踏み台サーバを立てる
  • プライベートサブネットに検証サーバを立てる
  • ssh configで踏み台経由でサーバにアクセスする設定を行う
  • ssh <設定名>でいつでもアクセスできるWHYYYYYYY
    やっていることのほとんどはAWSEC2のデザインパターンとかでよくみるやつです。

VPCの作成

まずは、VPCを作成します。
AWSのユーザーコンソールからVPCに移動

設定項目 設定値
名前タグ 適当な名前で
IPv4 CIDRブロック なんでもいいけどVPCにいっぱいサーバを立てるなら10.0.0.0/16が順当かと
IPv6 CIDRブロック ブロックはなしで
テナンシー デフォルトでOK

パブリックサブネットとプライベートサブネットを立てる

続いてサブネットを作ります。
ユーザーコンソールからVPC -> サブネットに移動。
サブネットではインターネット経由でアクセスできるパブリックサブネットとプライベートサブネットを設定します。

  • パブリックサブネット側
設定項目 設定値
名前タグ 適当な名前で
VPC さっき作成したVPC名を指定
アベイラビリティーゾーン 今回は特に指定なしでOK
IPv4 CIDRブロック VPCで設定したブロック内で範囲を指定。今回は10.0.1.0/24としておく。
  • プライベートサブネット側
設定項目 設定値
名前タグ 適当な名前で
VPC さっき作成したVPC名を指定
アベイラビリティーゾーン 今回は特に指定なしでOK
IPv4 CIDRブロック VPCで設定したブロック内で範囲を指定。今回は10.0.2.0/24としておく。

インターネットからパブリックサブネットにアクセスさせる設定

ここは大事なところ。 2つサブネットを作成した後に、パブリックサブネットのみ選択して、サブネットのアクション-> 自動割り当てIPの設定変更 に飛ぶ
そこで、 パブリックIPv4アドレスの自動割り当てを有効にする にチェック。
これをやっとかないと踏み台サーバ立てても外部からサーバにアクセスするための外部IPを発行してくれません。

次にやるのはインターネットとパブリックサブネットをつなぐゲートウェイ(窓口みたいなもの)の設定

  1. VPC -> インターネットゲートウェイに移動
  2. インターネットゲートウェイの作成を押して文字通り作成(名前は適当に)
  3. さっき作ったゲートウェイを選択して、 アクション->VPCのアタッチを選択
  4. VPCでさっき作ったVPCを選択してアタッチ
  5. VPC -> ルートテーブルに移動
  6. 作ったVPCに紐づくルートテーブルを選択。
  7. 下部にあるルートタブを選択して編集。
  8. 別のルートを追加を選択。以下のように設定
送信先 ターゲット
0.0.0.0/0 さっき作ったゲートウェイの名前

これでできました。

パブリックサブネットに踏み台サーバを立てる

ここから踏み台サーバを立てます。
サーバの立て方は基本的な方法と同じなので割愛。
一般的な立て方と違うのは以下の点。 + インスタンスのタイプはt2.nano(踏み台用途なので and 24時間稼働を想定してなるべくお金がかからないように) + インスタンスの詳細の設定にて + ネットワーク -> 作ったVPCの名前 + サブネット -> パブリックサブネットの名前

プライベートサブネットに検証サーバを立てる

今度はプライベート側に実際に使用するサーバを立てます。
こちらも基本的な立て方は同じ。
変更点は以下の点 + インスタンスの詳細の設定にて + ネットワーク -> 作ったVPCの名前 + サブネット -> プライベートサブネットの名前 + セキュリティグループは基本的に全開放でも問題ないが、気にされる方は必要なポートをパブリックサブネットのIPに指定するとよし。

ssh configで踏み台経由でサーバにアクセスする設定を行う

サーバが立てられたので、sshでつなぐ設定をします。 今回はmacを想定し、macの.ssh/configに設定をします。

# ~/.ssh/config
Host humidai
        HostName <踏み台サーバのパブリックIP>
        User ubuntu #サーバによって変化
    Port 22 #sshポート
        GatewayPorts yes
        IdentityFile ローカルマシン内で踏み台サーバの公開鍵が置いてある場所

Host server
        HostName <10.0.2.xxとなるIP>
        User ec2-user #サーバによって変化
        Port 22
        GatewayPorts yes
        ProxyCommand ssh -CW %h:%p humidai #humidaiは上記設定したHostの名前を指定
        IdentityFile ローカルマシン内で検証サーバの公開鍵が置いてある場所

# ProxtCommandが踏み台サーバ経由でsshサクセスさせるためのコマンド

この設定をした後、

ssh server

とコマンドを入力すると、踏み台経由でアクセスできます。
しかも、検証サーバを一旦落として再度あげてもプライベートIPは変わらないので、そのままsshコマンドで入れます。
また、ポートフォワーディングしたい場合は、

# ~/.ssh/config

#踏み台側
   LocalForward 5432 localhost:5432
      LocalForward 8080 localhost:8080
#サーバ側
        LocalForward 5432 <サーバのプライベートIP>:5432
        LocalForward 8080 <サーバーのプライベートIP>:8080

と設定すればOK

懸念事項

  1. この構成にすると、サーバ側からインターネットにつなぐことができないので、wgetとかでファイルを落としたりすることはできません。
    これについては別途NATインスタンスとかNATゲートウェイが必要になるのですが、いずれにしてもお金がかかる。。。。
    なので、しょっちゅうインターネットにアクセスしないのであれば、ローカルマシンに対象ファイルを落としてscpコマンドで移動がよいかなと。
    実際scpコマンドで移動させる場合でも
scp <移動させるファイル> server:/home/ec2-user

みたいな感じで簡単に移動できます。

  1. この構成は踏み台サーバは常時稼働を想定しています。踏み台サーバはt2.nanoの最小構成なので、
    $0.0058 /1 時間 -> 500円くらい/1ヶ月
    が必要経費になります。

ただ、毎回毎回IPアドレスを変える手間とか、めんどくさくてサーバをずっと起動させることによる課金等を考えると決して高い値段ではないかなと。

終わりに

今回は最近良くやるAWSでの検証サーバ構築用のシステムを紹介しました。
上述したように、この構成は本番構成でもやるような部分も含まれていますので、特にAWS初心者の方はぜひチャレンジしてみるといいかもしれません。

ホントの最後に

間違いとか、わからないとこがあればコメントとかしていただければ!!

Lambdaで署名付きURLを生成する方法(2018年3月)

以前からちょくちょく署名付きURLを作成していたのですが、それを久々に使ったところ、
なぜかエラーがでてたので、今の時点で使えるようにアップデートしました。

同じ情報はググればいっぱい出てくるのですが、どこも中途半端だったり、わかりにくかったりするので、
ここではURLが生成されるならよいという仕様で行きます。

環境

コード

#下2行は決まり文句的なもの
import boto3
def lambda_handler(event, context):

#BUCKET = '<バケット名>'
#KEY = '<ファイル名(パス含む)>'

  BUCKET = 'hogehoge'
  KEY = 'foo/bar.jpg'

  s3 = boto3.client('s3')

#URLを生成
#ExpiresInでURLの有効期限を設定

  url =  s3.generate_presigned_url(
      ClientMethod = 'get_object',
      Params = {'Bucket' : BUCKET, 'Key' : KEY},
      ExpiresIn = 604800,
      HttpMethod = 'GET'
  )

#生成したURLを出力
  print (url)   

    

注意点

  • 冒頭の決まり文句的なものが入っているか
  • インデントがきちんとされているか(カッコとセミコロンの後は特に注意)

うまくいかなかったらコメントくださいな。

自己紹介的な

はじめまして。

今更ながら技術ブログをはじめてみることにしました。

普段は主にBI・DWH界隈に生息しており、
ツールの導入支援、レポート開発(JavaJavascript等)、DWH設計ならびにETL構築支援等コンサルを主に行っています。

また並行してビッグデータがらみの調査・検証もしており、
主に分散システム(Hadoop、Spark、Kafka)あたりが最近のマイブームです。

このブログではそうした日々の何気ないことから発見した技術的なTipsや
技術本の感想みたいなものを行っていこうと考えています。

技術的興味関心キーワード